Java 的 CMS 垃圾回收流程是怎样的?
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 调优策略
- 增大堆内存:适当增大年轻代和老年代的大小,以减少GC频率。
- 调整年轻代比例:根据应用的对象创建和生命周期调整年轻代和老年代的比例。
- 设置触发阈值:通过
-XX:CMSInitiatingOccupancyFraction设置老年代的触发阈值,提前触发CMS以减少停顿时间。 - 使用并行GC:结合
-XX:+UseParNewGC使用并行年轻代收集器,以提升吞吐量。 - 监控GC日志:启用GC日志,分析回收过程中的停顿时间和内存使用,帮助优化。
部分参数含义
- **
-XX:NewRatio**:控制年轻代与老年代的比例。 - **
-XX:SurvivorRatio**:设置Eden区与Survivor区的比例,影响对象在年轻代中的存活情况。 - **
-XX:CMSInitiatingOccupancyFraction**:指定老年代达到此阈值时启动CMS回收。 - **
-XX:CMSMaxAbortablePrecleanTime**:设置CMS预清理阶段的最大时间,以防止过长的停顿。 - **
-XX:+UseCMSInitiatingOccupancyOnly**:仅根据CMSInitiatingOccupancyFraction进行CMS回收,不在其它情况下触发。
Comments