Jvm垃圾回收

发布于 2019-12-15 12:12 6209 字 32 min read

issyuu avatar

issyuu

喧噪から離れた「湖心小築(Lakeheart Retreat)」。静かな水辺で紡ぐ、思考と日常の断片

本文暂无中文翻译,显示原文内容
好记性不如烂笔头.

前言

  • 系统在运行的过程中, 会创建许许多多的对象, 这些对象会经历生老死的历程, 而那些’死’的对象需要进行回收为新生对象提供空间.

回收算法

引用计数算法

描述
  • 每个对象均配有一个引用计数器, 当对象被引用一次, 计数器+1, 反之移除对该对象的引用时,计数器-1, 当值为 0 时, 将被 GC 列为回收对象.
优点
  • 算法简单
缺点
  • 当出现循环依赖时, 造成彼此间计数器不为 0, 则不能被 GC 回收, 因此产生内存泄漏问题
例子
代码
public class ReferenceCountTest {

    public static void main(String[] args) {
        ReferenceObject object01 = new ReferenceObject(); // Step 01
        ReferenceObject object02 = new ReferenceObject(); // Step 02

        object01.setInstance(object02); // Step 03
        object02.setInstance(object01); // Step 04

        object01 = null; // Step 05
        object02 = null; // Step 06
    }
}

class ReferenceObject {

    private Object instance;

    public ReferenceObject setInstance(Object instance) {
        this.instance = instance;
        return this;
    }
}
图解
分析
  • Step 01: ReferenceObject01 实例引用计数+1 计数器 01=1
  • Step 02: ReferenceObject02 实例引用计数+1 计数器 02=1
  • Step 03: ReferenceObject02 实例引用计数+1 计数器 02=2
  • Step 04: ReferenceObject01 实例引用计数+1 计数器 01=2
  • Step 05: ReferenceObject01 实例引用计数- 1 计数器 01=1
  • Step 06: ReferenceObject02 实例引用计数- 1 计数器 02=1
结果
  • 循环依赖时, 造成彼此间计数器不为 0, 则不能被 GC 回收, 因此产生内存泄漏问题

可达性分析算法

描述
  • GC Roots节点向下搜索, 所走的路径称之为’引用链’, 当一个对象对 GC Roots 节点没有任何引用链相连接时, 则认为该对象是不可用的(即使该对象还与其他对象相关联).
例子
代码
public class FinalizeEscapeGC {

    public static FinalizeEscapeGC HOOK = null;

    public void log(){
        System.out.println("I am still alive.");
    }

    public static void main(String[] args) throws Throwable{
        System.out.println("gc roots tracing start.");

        HOOK = new FinalizeEscapeGC();

        HOOK = null;
        /** 对象不可达, 进行自救 {@link FinalizeEscapeGC#finalize()}, finalize()仅且执行一次. 自救成功*/
        System.gc();

        TimeUnit.SECONDS.sleep(1); // 执行筛选'F-Queue'的线程优先级较低, 休息一下...
        if(Objects.nonNull(HOOK)){
            HOOK.log();
        }else{
            System.out.println("oh, I am dead.");
        }

        HOOK = null;
        /** 对象不可达, 进行自救, 因finalize()仅且执行一次, 将不再执行, 自救失败 */
        System.gc();

        TimeUnit.SECONDS.sleep(1); // 执行筛选'F-Queue'的线程优先级较低, 休息一下...
        if(Objects.nonNull(HOOK)){
            HOOK.log();
        }else{
            System.out.println("oh, I am dead.");
        }

        System.out.println("gc roots tracing end.");
    }

    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        System.out.println("help me!!!");
        HOOK = this;
    }
}
输出
gc roots tracing start.
help me!!!
I am still alive.
oh, I am dead.
gc roots tracing end.
分析
  • 经可达性分析算法所标记的对象, 会经过第一次标记与筛选(有没有必要执行 finalize() (对象有没有覆盖 finalize()方法)):
    • 有必要, 将对象放入F-Queue队列中, 稍后由 Jvm 自动创建一个低优先级FinalizerThread执行扫描该队列, 进行第二次筛选(执行 finalize() 俗称: 自救), 对象在该过程期间是否与引用链上的任何一个对象建立关联:
      • 有, 从回收集合中移除;
      • 没有, 进行回收
    • 没有必要, 加入回收集合;
使用 finalize 注意
  • FinalizerThread是一个低优先级的线程, 启动后F-Queue队列中的元素排队执行finalize()方法, 使用不合理情况下, 将导致这些对象长时间堆积在内存中, 到达已经程度可能会引发OOM;
GC Roots 对象包含 (但不限于)
  • 启动类(Bootstrap)加载的类和创建的对象;
  • 栈中引用的对象(栈帧中的本地变量表引用的对象);
  • 元数据区类静态属性引用的对象;
  • 元数据区常量引用的对象;
  • JNI(Native 方法)引用的对象;
引用
  • 分为, 强引用, 软引用, 弱引用, 虚引用. 引用强度依次逐渐减弱
强引用(Strong Reference)
  • 类似Object obj = new Object();, 可以直接访问目标对象, 强引用执行的对象在任何时候都不会被系统回收(Jvm 宁愿抛出OOM, 也不会回收强引用所指向对象, 因此可能会导致内存泄漏);
软引用(Soft Reference)
  • SoftReference 来实现软引用, 用来描述一些还有用但非必需的对象, 在系统要发生内存溢出之前, 将这些对象列入回收范围进行回收. 若回收后还不足用于创建新对象的空间, 则抛出OOM;
弱引用(Weak Reference)
  • WeakReference 来实现弱引用, 用描述一些非必需的对象, 只能生存到下一次垃圾收集发生之前(无论内存是否充足, 都是回收);
虚引用(Phantom Reference)
  • PhantomReference 来实现虚引用, 对象是否有虚引用的存在, 完全不会对其生存时间构成影响, 无法通过虚引用来取得一个对象实例;
  • 作用: 可以在垃圾收集器回收时收到一个通知;

垃圾回收算法

标记-清除算法

描述
  1. 标记存活的对象;
  2. 统一回收未标记的对象;
标记-清除算法
标记-清除算法
缺点
  • 效率问题(执行期间会Stop The World)
  • 空间问题(容易产生大量不连续的空间碎片, 无法分配大对象, 会导致频繁Minjor GC, 以至导致Full GC, 最终OOM)
总结
  • 适用于单核机器上;

标记-整理算法

描述
  • 该算法是对’标记-清除算法’的优化;
  1. 标记存活对象;
  2. 存活对象向一端一端, 清理存活边界以外内存;
标记-整理算法
标记-整理算法
优点
  • 不会产生内存碎片;
总结
  • 该算法适用于对象’存活率高’的区域;
  • 适用于老年代区;

标记-复制算法

描述
  1. 标记存活对象;
  2. 将存活对象复制到另外一半内存;
  3. 清除当前这一半的内存区域;
标记-复制算法
标记-复制算法
优点
  • 对象存活率低, 复制的对象就少, 进而效率高(每次最多浪费 10%的内存(Eden : Survivor From : Survivor To = 8 : 1 : 1));
缺点
  • 可使用内存只有一半(该算法不适合对象存活率较高场景, 老年代一般不采用该算法);
总结
  • 该算法适用于对象’存活率低’的区域;
  • 适用于新生代(Eden)区

垃圾收集器

Serial 收集器

垃圾收集器-Serial
垃圾收集器-Serial
描述
  • 基于’标记-复制算法’的单线程收集器;
  • 单线程收集器, 执行期间用户线程暂停(俗称:Stop The World(STW));
使用方式
-XX:+UseSerialGC  
总结
  • 适用于新生代;
  • 在单核机器上适用场景较多;

ParNew 收集器

垃圾收集器-Serial
垃圾收集器-Serial
描述
  • 基于’标记-复制算法’ ‘并行’的多线程收集器(Serial 收集器的多线程版本);
  • 以获取最短回收停顿时间为目标的收集器;
  • 默认垃圾收集线程数与 CPU 数量相同;
使用方式
-XX:+UseParNewGC 
-XX:ParallelGCThreads=n // 设置垃圾收集的线程数
总结
  • 适用于新生代;

Parallel Scavenge 收集器

描述
  • 基于’标记-复制算法’ ‘并行’的多线程收集器;
  • 以吞吐量优先的收集器(运行用户代码时间/(运行用户代码时间 + 垃圾回收时间));
使用方式
-XX:+UseParallelGC 
-XX:MaxGCPauseMillis=n // 设置最大垃圾收集停顿时间 n(ms) (停顿时间缩短是以牺牲吞吐量和新生代(Eden)区来换取), 过小会导致频繁GC, 默认: 200
-XX:GCTimeRatio=n // 设置吞吐量大小 n%
-XX:+UseAdaptiveSizePolicy // 自适应调节策略(根据当前系统运行情况收集性能监控, 动态调整'-Xmn','-XX: SurvivorRatio', '-XX: PretenureSizeThreshold'以提供最合适的停顿时间和最大的吞吐量)
总结
  • 适用于新生代;
  • 未知情况下, 可使用自适应调节策略来动态调整(出现问题时, 会增大排除问题难度…);

Serial Old 收集器

描述
  • 基于’标记-整理算法’的单线程收集器;
  • 单线程收集器, 执行期间用户线程暂停(俗称:Stop The World(STW));

Parallel Old 收集器

描述
  • 基于’标记-整理算法’ ‘并行’的多线程收集器;
  • 以吞吐量优先的收集器
使用方式
-XX:+UseParallelOldGC 

CMS(Concurrent Mark Sweep) 收集器

垃圾收集器-CMS
垃圾收集器-CMS
描述
  • 以获取最短回收停顿时间为目标的收集器;
  • 基于 标记-清除算法实现的;
  • CS(Collection Set): 一组可被回收的 Region 的集合; 解决并发标记阶段, Old -> Young 或 Young -> Old 跨代引用的问题;
    • Points-Out(我引用了谁的对象)
  • 步骤:
    1. 初始化标记(STW: 速度很快)
    2. 并发标记
    3. 预清理
    4. 可被终止的预清理
    5. 重新标记(STW: 持续时间最长)
    6. 并发清除
    7. 并发重置状态

初始化标记(STW)
垃圾收集器-CMS-初始化标记
垃圾收集器-CMS-初始化标记
  • 标记老年代所有 GC Roots 对象(从根集合可直接到达的对象);
  • 标记年轻代所有 GC Roots 引用老年代的对象;
  • 该阶段是基于单线程的, 可通过”-XX: +CMSParallelInitialMarkEnabled” 和 ‘-XX: ParallelGCThreads=n’ 来调改变单线程的操作, 开启并行处理;
并发标记
垃圾收集器-CMS-并发标记
垃圾收集器-CMS-并发标记
  • 从 GC Roots 进行追踪(tracing), 找出并标记所有存活对象;
  • 因该阶段与用户线程并发执行, 可能会引发”Concurrent Model Failure”;
垃圾收集器-CMS-应用程序操作导致
垃圾收集器-CMS-应用程序操作导致
  • 该阶段是与用户线程并发执行的, 运行过程中, 对象可能存在多种情况: “新生代对象普生至老年代”, “大对象直接进入老年代”, “老年代中对象间引用关系变动”. 为杜防这些情况发生, 会将这些对象重新标记, 对象对应 Card 上的标识改为Dirty(并发标记阶段只负责标识, 重新标记阶段会只扫描这些的对象, 避免扫描整个老年代.);
预清理
垃圾收集器-CMS-预清理02
垃圾收集器-CMS-预清理02
  • 处理并发标记阶段 Card 上标识为Dirty的对象;
可被终止的预清理
  • 尝试分担重新标记阶段的工作;
  • 该阶段是重复做相同的事情, 直到发生abort的条件(重复次数, 持续时间等), 可通过”-XX
    =n” , “-XX
    =n”, “-XX
    =n”等参数来调整;
重新标记(STW)
  • 标记老年代所有的存活对象, 重新扫描整个堆;
    • 因老年代中的对象可能被新生代中对象引用, 所以需要扫描新生代;
      • 因扫描时, 会使用新生代中不可达的对象当做”GC Roots”对象, 来扫描老年代. 当这些不可达的对象引用老年代中对象太多情况下, 会导致该阶段耗时过长(实际这些扫描是没必要的). 出现这种情况下可通过”-XX: +CMSScavengeBeforeRemark”来优化该阶段, 在重新标记前, 先执行一次”YGC”, 回收不可达的对象, 可达的对象移入幸存区(Survivor)或老年代, 以减少年轻代对老年代的无效引用, 再执行重新标记时, 只需扫描幸存区即可, 这样就减少了扫描时间.
  • 该阶段是基于单线程的, 可通过”-XX: +CMSParallelRemarkEnabled”开启并行处理;
并发清除
  • 根据清除算法清除不可用对象回收内存空间;
  • 因基于”并发-标记-清除”算法, 清除后不会对内存做整理, 可能就会出现内存碎片, 造成 OOM, 可通过”-XX: +UseCMSCompactAtFullCollection”和”-XX: CMSFullGCsBeforeCompaction=n”指定执行’n’次后做一次内存整理(默认: 0, 每次 Full GC 都会执行内存整理);
  • 因该阶段与用户线程并发执行, 可能会产生新的垃圾, 这部分垃圾称为”浮动垃圾”, 留在下次 GC 时清除;
并发清除
  • 清除内部状态
使用方式
-XX:+UseConcMarkSweepGC // 开始使用CMS垃圾收集器
-XX:+CMSScavengeBeforeRemark // "重新标记"阶段前, 先执行一次YGC
-XX:+ScavengeBeforeFullGC // "并发清除"阶段前, 先执行一次YGC
-XX:UseCMSInitiatingOccupancyOnly // 配置JVM不基于运行时收集的数据来动态调整垃圾收集周期(关闭自适应调节策略)
-XX:CMSInitiatingOccupancyFraction=n // 配置JVM在老年代内存占用达到n%时触发GC(需搭配"-XX: UseCMSInitiatingOccupancyOnly"使用, 否则仅在第一次使用该配置, 后续依然使用自适应调节策略) 默认: 92
-XX:+UseCMSCompactAtFullCollection // 开启对老年代进行内存整理, 以消除内存空间碎片化
-XX: CMSFullGCsBeforeCompaction=n // 执行n次后进行内存整理
-XX:+CMSParallelInitialMarkEnabled // 初始化标记阶段开启并行操作
-XX:+CMSParallelRemarkEnabled // "重新标记"阶段开启并行操作
-XX:ParallelGCThreads=n // 并发回收线程数, 默认: (cpus <= 8) ? cpus : 3 + ((cpus * 5) / 8)
-XX:CMSMaxAbortablePrecleanTime=n // 预清理阶段, 最大持续时间(ms) 默认: 5000
-XX:CMSScheduleRemarkEdenPenetration=n // "可被终止的预清理"阶段, Eden区域内存达到n%后, 进入"重新标记阶段"阶段, 默认: 50
-XX:CMSScheduleRemarkEdenSizeThreshold=n // "可被终止的预清理"阶段, Eden区域内存达到nM后, 进入"重新标记阶段"阶段, 默认: 2

-XX:+CMSIncrementalMode // (i-cms)增量的进行垃圾收集, 并发阶段, 不会独占整个周期, 周期性暂停, 唤醒应用线程. 收集器把并发工作划分为片段, 安排在次级(minor)回收间执行(在少量CPU, 需低延迟服务器上优势会高些).
-XX:+CMSIncrementalPacing // 开启基于运行时收集的数据动态调整垃圾回收任务的数量
-XX:CMSIncrementalDutyCycle=n // 每次增量回收垃圾占总垃圾的比例   默认: 10
-XX:CMSIncrementalDutyCycleMin=n // 每次增量回收垃圾站总垃圾的最小比例 默认: 0

-XX:ExplicitGCInvokesConcurrent // System::gc时做background模式的Full GC(默认会STW)
-XX:+DisableExplicitGC // 禁止在运行期间显式调用System::gc

-XX:-ReduceInitialCardMarks // 禁止并发初始化新对象与RS更新放到一起执行
问题
Concurrent Model Failure
  • GC 执行过程中, 用户线程也在运行, 当年轻代空间不足时触发”Minjor GC”, “Minjor GC”执行过程中可能会有幸存者进入老年代, 此时老年代内存不足, 然后就抛出”concurrent mode failure”;
  • 可通过”-XX: +UseCMSInitiatingOccupancyOnly”和”-XX: CMSInitiatingOccupancyFraction=n” 合理配置来解决该问题;
Promotion Failed
  • GC 执行过程中, “Survivor Space”空间不足, 对象直接进入老年代, 此时老年代内存不足, 然后抛出”promotion failed”(可能是老年代空间足够, 是碎片化的, 转入老年代的对象找不到连续的空间存放导致的);
    • 过早提升: Minor GC 过程中, “Surevivor To” 不足以存储”Eden”和”Surevivor From”中存活的对象, 多余的对象将被移入老年代(该种情况可调整 Survivor 空间大小);
  • 视情况而定, 可通过”-XX: CMSFullGCsBeforeCompaction=n”进行空间整理……
缺点
  • 只回收老年代, 以吞吐量换取停顿时间;
  • 应用长时间运行情况下, 容易造成严重的内存碎片化(可解决);
  • 无法解决浮动垃圾问题;

G1 收集器

垃圾收集器-G1
垃圾收集器-G1
描述
  • 使用相对较短的停顿时间来达到最大吞吐量的收集器;

  • SATB(Snapshot At The Beginning): 并发标记阶段, 用户线程与垃圾收集线程并发执行, 就可能出现突变者(对象被引用或取消引用),根据”三色标记法”维护并发 GC 的正确性;

    • 白色: 对象没有被标记到, 标记阶段结束后, 会被当做垃圾回收掉;
    • 灰色: 对象已被标记, 但里面还有 field 没有被标记;
    • 黑色: 对象已被标记, 且里面所有 field 也已被标记;
  • TAMS(Top At Mark Start): 解决并发标记阶段, 新对象被 new, 但未被引用, 而导致漏标的情况;

    • 并发标记中用到的两个 Bitmap
      • prev Bitmap: 记录第 n-1 轮 Concurrent Marking 所得的对象存活状态. (由于第 n-1 轮 Concurrent Marking 已经完成, 这个 Bitmap 的信息可以直接使用);
      • next Bitmap: 记录第 n 轮 Concurrent Marking 的结果. (这个 Bitmap 是当前将要或正在进行的 Concurrent Marking 的结果, 尚未完成, 所以还不能使用);
    • Region 中几个指针
      垃圾收集器-G1-Region内指针
      垃圾收集器-G1-Region内指针
      • (Bottom - Top): 已使用的空间;
        1. (Bottom - Prev TAMS): 已确定存活的对象;
        2. (Prev TAMS - Next TAMS): 在第 n-1 轮 Concurrent Marking 隐式存活的对象;
        3. (Next TAMS - Top): 在第 n 轮 Concurrent Marking 隐式存活的对象;
      • (Top - End): 尚未使用, 可分配的空间;
  • RS(Remembered Set): 解决并发标记阶段, Old -> Young 或 Young -> Old 跨代引用的问题;

    • 每个 Region 附有个 RS, 用于记录其他 Region 中的对象引用本 Region 中对象的关系, Points-Into(谁引用了我)
  • CS(Collection Set): 一组可被回收的 Region 的集合;

  • TLAB(Thread Local Allocation Buffer): 本地线程缓冲区, 为了使对象尽快分配到内存空间, 每个线程都有固定的分区用于分配对象;

  • Humongous: 存放大对象的 Region(空间占 Region 一半及以上的对象)

    • 在 Mixed GC 和 Full GC 回收
  • 步骤:

    1. 初始化标记(STW: 速度很快)
    2. 并发标记
    3. 最终标记(STW)
    4. 清理(STW)

初始化标记(STW)
  • 标记 GC Roots 对象(从根集合可直接到达的对象);
  • 将字段压入扫描栈(marking stack), 等待后续的扫描;
  • 使用外部 bitmap 记录扫 mark 信息(未使用对象头中 mark word 里的 mark bit 来记录);
并发标记(并发)
  • 从扫描栈中取出对象引用, 递归扫描整个堆获取的对象图;
  • 对对象图上对象标记, 压入扫描栈;
  • 重复执行上两步, 知道扫描栈为空;
  • 扫描 SATB write barrier 所记录的引用(扫描栈中执行完, 就撤出);

===================

  • 该阶段是并发进行的, 就需要解决程序进行的过程中未标, 漏标的情况. G1 通过 Writer barrier(Logging barrier)来实现;
最终标记(STW)
  • 扫描并发标记后剩下的 SATB write barrier 所记录的引用;
  • 扫描弱引用;
清理(STW)
  • 清除未标记的对象(将 Region 中存活(标记过)的对象拷贝到空的 Region 中, 回收原 Region);
    • 可以自由选择任意多个 Region 来独立构成收集集合 CS(Collection Set)(靠 Per-Region Remembered Set 实现);
    • 选择 CS 后, 采用并行复制算法将 CS 中每个 Region 里存活的对象拷贝到新的 Region 中;
    • 回收原 Region;
  • 重置标记状态;
模式
  • Young GC
    • 当年轻代无法分配新对象时, 选定所有年轻代里的 Region 进行收集清理(可通过控制年轻代里的 Region 个数来控制 Young GC 的开销(-XX
      =n))
  • Mixed GC
    • 视全局并发标记后统计, 选定所有年轻代里的 Region 进行收集清理, 根据 Global Concurrent Marking 统计得出收集收益高的若干老年代里的 Region, 在用户指定的开销目标范围内尽可能选择收益高的老年代里的 Region 进行收集清理;
      • Global Concurrent Marking 主要是为 Mixed GC 提供服务,

==================

  • Full GC(G1 GC 的控制范围内没有 Full GC)
    • 若 Mixed GC 无法跟上程序分配内存的速度, 导致老年代填满无法继续进行 Mixed GC, 就默认采用 Serial Old 算法(和 -XX:+UseSerialGC 一样)堆整个堆内存进行收集清理;

  • Young GC 与 Mixed GC 之间视运行情况切换, 虚拟机会定时做全局并发标记;
    • 初始化标记默认在 Young GC 阶段执行;
    • 全局并发标记进行时, 虚拟机不会执行 Mixed GC;
    • Mixed GC 进行时, 虚拟机不能执行初始化标记;
    • Tip: 正常流程中没有 Full GC, 老年代里的 Region 收集清理靠 Mixed GC 来完成.(视用户 Jvm 配置与程序运行情况而定);
使用方式
-XX:+UseG1GC // 开启使用G1垃圾收集器
-XX:G1HeapRegionSize=nm // 设置G1区域(Region)大小(范围 1 ~ 32MB), 堆为 2048 * Region (为减少过多分配Humongous对GC的影响, 特殊场景下可适当调整大小)
-XX:MaxGCPauseMillis=n // 期望GC最大的暂停时间, 默认: 200
-XX:ParallelGCThreads=n // GC过程中并行线程数, 默认: cpu <= 8 时, 8; >8时, 5/8 * cpu core
-XX:G1ConcRefinementThreads=n // 扫描log Buffer, 更新Rset时, 并发优化线程数
-XX:ConcGCThreads=n // 并发标记线程数, 默认: -XX:ParallelGCThreads 的1/4
-XX:+ParallelRefProcEnabled // 开启并行对象引用处理
-XX:ReferencesPerThread=n // 处理对象引用并行线程数, 最大线程数受 -XX:ParallelGCThreads 限制
-XX:NewRatio=n // 新老年代比例, 默认: 2 (1:2)
-XX:SurvivorRatio=n // Survivor与Eden比例, 默认: 8 (2:8)
-XX:G1NewSizePercent=n // 年轻代占堆的n%内存, 默认: 5
-XX:G1MaxNewSizePercent=n // 年轻代占堆的最大内存, 默认: 60
-XX:MaxTenuringThreshold=n // 对象在新生代经过n次YGC方可进入老年代, 默认: 15
-XX:InitiatingHeapOccupancyPercent=n // 触发标记的堆占用内存阈值(non_young_capacity_bytes: Old Generadion Region + Humongous), 默认: 45
-XX:G1HeapWastePercent=n // 愿意浪费堆的n%, Global Concurrent Marking后可回收内存小于n, 则不会触发Mixed GC, 默认: 5
-XX:G1ReservePercent=n // 预留G1HeapWastePercent堆的n%内存, 防止普升失败, 默认: 10
-XX:G1MixedGCLiveThresholdPercent=n // 一个Region中存活的对象超过n%, 就不会被认为可垃圾Region, 通过该参数可影响每次Mixed GC回收的Region数(n越大, 越容易被认为是垃圾分区), 默认: 85 [^1],[^2]
-XX:G1MixedGCCountTarget=n // 经过n次Mixed GC, 老年代所有Region将被回收一遍. 如果 Mixed GC中STW的时间过长, 可以考虑增大这个参数.(可用来调整每次Mixed GC回收多少个Region, 即有助于调节Mixed GC的停顿时间), 默认: 8 [^3]
-XX:G1RSetUpdatingPauseTimePercent=n // GC 清除阶段更新RSet的时间百分比, 默认: 10

-XX:+G1SummarizeRSetStats // 显示RS粗化过程
-XX:G1SummarizeRSetStatsPeriod=n // 每隔n次GC后收集一次RS的统计信息
-XX:+PrintAdaptiveSizePolicy // 打印"自适应调节策略"模式下运行的决策细节
-XX:+PrintReferenceGC // 打印详细的引用信息
优点
  • 并行性: 回收期间, 可由多个 GC 线程同时工作, 有效利用多核计算能力;
  • 分代 GC: 同时兼顾年轻代与老年代;
  • 空间整理: 在每次回收时有效的复制对象, 减少空间碎片;
  • 停顿时间可控: 在停顿时间上添加了预测机制, 收集器将根据用户指定期望停顿时间回收收益率越高的 Region;
缺点
  • Region 空间的大小与大对象占用空间很难保证一致, 这将导致空间浪费(Region 设置过小, 分配超过一个 Region 空间的大对象时, 有时寻找连续的空间会有麻烦);
总结
  • 清理算法区别
    • G1 的清理算法从根集合遍历对象图来判定对象的生死, 不需要依赖 Global Concurrent Marking 的结果, 有就用, 没有也行;
    • 标记-清除算法依赖于标记阶段对对象生死的判定;

引用

工具

案例

常用参数

-verbose: gc 或者 -Xlog:gc
-XX:+PrintGCDateStamps // 打印GC的时间戳
-XX:+PrintGCDetails  // 打印详细的GC日志
-XX:+PrintGCApplicationStoppedTime // 打印GC期间应用停止响应的时间
-XX:+PrintGCApplicationConcurrentTime // 答应GC期间应用运行时间

-XX:+UseGCLogFileRotation // 滚动输出GC日志
-XX:NumberOfGCLogFiles=10 
-XX:GCLogFileSize=10M
-Xloggc: /home/XX/gc/XX_gc.log

-XX:NewRatio=n // 新老年代比例(默认: 2 (1:2))
-XX:SurvivorRatio=n // Survivor与Eden比例(默认: 8 (2:8))
-XX:MaxTenuringThreshold=n // 对象在新生代经过n次YGC方可进入老年代(默认: 15)

-XX:+UnlockDiagnosticVMOptions    //后面2个参数的需要
-XX:+PrintCompilation   //打印JIT编译详情
-XX:+PrintInlining    //打印内联详情

// OOM输出
-XX:+HeapDumpOnOutOfMemoryError 
-XX:HeapDumpPath=/home/XX/dump_OOME.hprof

-XX:+DisableExplicitGC

// 收集器
-XX:+UseSerialGC // 串行收集器
-XX:+UseParallelGC // 并行收集器
-XX:+UseParalledlOldGC // 并行老年代收集器
-XX:+UseConcMarkSweepGC // 并发收集器

标注

喜欢的话,留下你的评论吧~

© 2020 - 2026 issyuu @Lakeheart Retreat
Powered by theme astro-koharu · Inspired by Shoka