zoukankan      html  css  js  c++  java
  • GC回收算法&GC回收器

    垃圾标记

    在回收垃圾前,需要判断哪些是垃圾,哪些不是。

    引用计数法

    原理:被引用+1,未被引用-1,为0时回收。

    问题:无法解决循环引用的问题

    • 什么是循环引用?(环)

      A 引用了 B,B 引用了 C,C 引用了 A,它们各自的引用计数都为 1。但是它们三个对象却从未被其他对象引用,(假设有1000个对象时,这三个就是垃圾;如果只有4个对象,那么另外一个就是垃圾)只有它们自身互相引用。从垃圾的判断思想来看,它们三个确实是不被其他对象引用的,但是此时它们的引用计数却不为零。

    可达性分析(主流使用)

    通过GC Roots作为起点遍历,判断是否被引用。

    GC Roots包括:

    • 虚拟机栈中引用的对象
    • 方法区静态属性引用的对象
    • 方法区常量引用的对象
    • JNI引用的对象(Native方法)

    【引用的判定】

    • 强引用:抛异常也不回收
    • 软引用:内存空间不够就回收
    • 弱引用:发现了就回收(按线程优先级)
    • 虚引用:任何时刻都会被回收

    GC回收算法

    分代收集本质上就是分类讨论,根据对存活对象的预判,采用效率更高的收集算法。

    标记-清除算法(适合老年代)

    先通过GC Roots遍历,标记不可达对象,而后清除。

    问题:产生不连续的空间碎片

    标记-复制算法(适合年轻代)

    折半内存,将存活对象复制到另一半内存中,然后把当前内存全部回收。

    问题:解决了空间碎片,但只能使用一半的内存

    标记-整理算法(适合老年代)

    将存活对象移动到内存的一端,然后清除边界之外的所有内存。

    【既不会产生空间碎片,也不会导致内存折半】

    “因地制宜”——分代算法

    分代算法,就是根据 JVM 内存的不同内存区域,采用不同的垃圾回收算法。

    例如对于存活对象少的新生代区域,比较适合采用复制算法。这样只需要复制少量对象,便可完成垃圾回收,并且还不会有内存碎片。

    而对于老年代这种存活对象多的区域,比较适合采用标记清除算法或标记整理算法,这样不需要移动太多的内存对象。

    GC回收器

    Serial 回收器

    Serial回收器是一种单线程串行回收器,使用复制算法,在执行回收时会产生较长时间的停顿,优点是不会产生线程切换的开销

    通过JVM参数-XX:+UseSerialGC可以使用串行垃圾回收器。

    Serial Old 回收器

    SO回收器是一种多线程并行回收器,使用标记整理算法,适用老年代

    ParNew回收器

    PN回收器是一种多线程并行器,使用复制算法。

    参数控制:-XX:+UseParNewGC

    Parallel Old回收器

    PO是一种多线程回收器,使用标记整理算法,适用老年代

    Parallel Scavenge回收器

    PS回收器也是一种多线程并行回收器,使用复制算法,特点是可设置吞吐量

    参数:-XX:+UseParallelGC

    CMS收集器

    CMS使用标记清除算法,主要目的是回收时的低停顿。

    过程:

    • 初始标记:单线程(触发停顿),标记与GC Roots关联的对象
    • 并发标记:标记不可达对象(可能产生回收对象,所以之后需要重新标记)
    • 重新标记:单线程(触发停顿),纠正标记
    • 并发清除:清除对象

    问题:

    • CPU资源消耗高
    • 浮动垃圾产生(回收时产生了新的垃圾)
    • 标记清除算法导致的空间碎片问题

    G1回收器

    特点:

    • 停顿时间:G1可充分利用多核多CPU的优势减少停顿时间,并且可建立可以预测的停顿模型,可设置停顿的时间
    • 支持分代回收,可使用分区策略同时兼顾老年代和年轻代
    • 使用标记整理算法,不会产生空间碎片

    分区思路:

    为什么使用分区:针对老年代的操作需要扫描所有的老年代空间;由于连续,必须分配年轻代和老年代的地址位置

    G1之前的内存都是连续的:

    image-20200730155606019

    G1回收器的内存按区等分,分为eden,survivor,old和humongous:

    image-20200730155714112

    G1回收器回收流程:

    • 初始标记
    • 并发标记
    • 重新标记
    • 并发回收

    Minor GC 和Full GC

    从年轻代空间(包括 Eden 和 Survivor 区域)回收内存被称为 Minor GC。当 JVM 无法为一个新的对象分配空间时会触发 Minor GC,比如当 Eden 区满了。

    Full GC 是清理整个堆空间—包括年轻代和永久代。

    Full GC执行条件:

    • 调用System.gc时,系统建议执行Full GC,但是不必然执行
    • 老年代空间不足
    • 方法区空间不足
  • 相关阅读:
    怎么解决Chrome浏览器崩溃“STATUS_INVALID_IMAGE_HASH”的问题
    Windows下PHP如何选择Thread Safe和Non ThreadSafe版本
    Windows环境下安装Yaf框架
    创建Redis-Cluster集群常见问题-解决方案
    Linxu下PHP版本升级
    Linxu下Yii2的POST提交被拒经历
    彻底搞懂 Redis 事务
    python模块之psutil详解
    iptables学习笔记
    incaseformat 病毒事件企业解决流程
  • 原文地址:https://www.cnblogs.com/noneplus/p/13441262.html
Copyright © 2011-2022 走看看