Java 的 CMS 垃圾回收流程是怎样的?

Sherwin.Wei Lv8

Java 的 CMS 垃圾回收流程是怎样的?

回答重点

1)初始标记(initial mark)

  • 在这个阶段,CMS 会进行一个快速的初始标记,标记所有根对象(如栈中的引用)直接可达的对象。此过程是 STW的,但时间较短。

2)并发标记(Concurrent marking)

  • 初始标记后,CMS 进入并发标记阶段。在此阶段,垃圾收集器与应用线程并发运行,从上一步标记的根直接可达对象开始进行 tracing,递归扫描所有可达对象。此阶段可能会持续较长时间。

3)并发预清理(Concurrent precleaning)

  • 这个阶段也是和应用线程并发,就是想帮重新标记阶段先做点工作,扫描一下卡表脏的区域和新晋升到老年代的对象等,因为重新标记是 STW 的,所以先分担一点。

4)可中断的预清理阶段(AbortablePreclean)

  • 这个和上一个阶段基本上一致,就是为了分担重新标记标记的工作,但是它可以被中断。

5)重新标记(remark)

  • 这个阶段是 STW 的,因为并发阶段引用关系会发生变化,所以要重新遍历一遍新生代对象、Gc Roots、卡表等,来修正标记。

6)并发清理(Concurrent sweeping)

  • CMS 进行并发清除阶段,标记为不可达的对象会被清除。此过程与应用线程并发运行,旨在减少停顿时间。

7)并发重置(Concurrent reset)

  • 这个阶段和应用线程并发,重置 cms 内部状态。

cms 的瓶颈就在于重新标记阶段,需要较长花费时间来进行重新扫描。

扩展知识

CMS 调优策略

  1. 增大堆内存:适当增大年轻代和老年代的大小,以减少GC频率。
  2. 调整年轻代比例:根据应用的对象创建和生命周期调整年轻代和老年代的比例。
  3. 设置触发阈值:通过-XX:CMSInitiatingOccupancyFraction设置老年代的触发阈值,提前触发CMS以减少停顿时间。
  4. 使用并行GC:结合-XX:+UseParNewGC使用并行年轻代收集器,以提升吞吐量。
  5. 监控GC日志:启用GC日志,分析回收过程中的停顿时间和内存使用,帮助优化。

部分参数含义

  • **-XX:NewRatio**:控制年轻代与老年代的比例。
  • **-XX:SurvivorRatio**:设置Eden区与Survivor区的比例,影响对象在年轻代中的存活情况。
  • **-XX:CMSInitiatingOccupancyFraction**:指定老年代达到此阈值时启动CMS回收。
  • **-XX:CMSMaxAbortablePrecleanTime**:设置CMS预清理阶段的最大时间,以防止过长的停顿。
  • **-XX:+UseCMSInitiatingOccupancyOnly**:仅根据CMSInitiatingOccupancyFraction进行CMS回收,不在其它情况下触发。
Comments