题目
CMS垃圾收集器的工作流程及Concurrent Mode Failure分析
信息
- 类型:问答
- 难度:⭐⭐
考点
垃圾收集器原理,内存回收机制,GC调优
快速回答
CMS(Concurrent Mark Sweep)收集器工作流程:
- 初始标记(STW):标记GC Roots直接关联对象
- 并发标记:与用户线程并行标记可达对象
- 重新标记(STW):修正并发标记期间的变动
- 并发清除:与用户线程并行清理垃圾
Concurrent Mode Failure触发条件:老年代空间不足时发生,导致Full GC。避免方法:
- 增大老年代空间(-XX:NewRatio)
- 降低触发阈值(-XX:CMSInitiatingOccupancyFraction)
- 启用内存碎片整理(-XX:+UseCMSCompactAtFullCollection)
一、CMS工作流程详解
CMS是针对老年代的并发收集器,通过减少STW时间提升响应速度:
- 初始标记(Initial Mark - STW)
暂停所有应用线程,标记GC Roots直接关联的对象(速度极快) - 并发标记(Concurrent Mark)
与应用线程并发执行,遍历对象图标记存活对象(耗时最长) - 重新标记(Remark - STW)
修正并发标记期间因用户线程运行导致的标记变动(使用增量更新算法) - 并发清除(Concurrent Sweep)
与应用线程并发执行,清理未标记的垃圾对象
二、Concurrent Mode Failure原理
当出现以下情况时触发:
在并发清理阶段,老年代空间不足以容纳新晋升的对象。此时JVM会中止CMS并发周期,立即触发Serial Old收集器进行Full GC(长时间STW)。
根本原因:
1. 老年代空间分配过小
2. 对象晋升速度过快
3. 内存碎片导致无法分配连续空间
三、避免策略与最佳实践
1. 参数调优
// 推荐配置示例
-XX:+UseConcMarkSweepGC
-XX:CMSInitiatingOccupancyFraction=70 // 老年代70%时启动CMS
-XX:+UseCMSInitiatingOccupancyOnly // 强制使用设定阈值
-XX:+UseCMSCompactAtFullCollection // FullGC时压缩内存
-XX:CMSFullGCsBeforeCompaction=5 // 每5次FullGC压缩一次
-XX:NewRatio=3 // 老年代/新生代=3:12. 监控与诊断
- 通过GC日志检测:
-Xlog:gc*:file=gc.log - 关键日志标识:
[Concurrent Mode Failure] - 使用工具分析:JVisualVM, GCViewer
3. 替代方案
当频繁出现Concurrent Mode Failure时,考虑:
- 升级到G1收集器:-XX:+UseG1GC
- 切换到ZGC(JDK11+):-XX:+UseZGC
四、常见错误
- 错误1:未设置
-XX:+UseCMSInitiatingOccupancyOnly导致JVM自动调整阈值 - 错误2:过度降低CMS触发阈值导致频繁GC
- 错误3:未启用内存压缩导致碎片化加剧
五、扩展知识
- CMS vs G1:G1通过Region分区和预测模型避免内存碎片问题
- 晋升担保失败:当Survivor空间不足时,对象会直接进入老年代,可能加剧Concurrent Mode Failure
- JDK版本影响:JDK8中CMS仍可用,JDK14后已被移除