CMS 收集器原理
候选人小冯在面试美团 P6 时,面试官问道:
"CMS 收集器的执行流程是什么?"
小冯说:"有初始标记、并发标记、重新标记..."面试官追问:"CMS 在哪个阶段会 Stop-The-World?"
小冯答不上来。面试官继续追问:"CMS 有什么缺点?"
小冯彻底卡住了...
一、核心问题:CMS 收集器原理 🔴
1.1 问题拆解
1.2 ❌ 错误示范
候选人原话 A:"CMS 是并发收集,整个过程都不停顿。"
问题诊断:CMS 的并发标记和并发清除阶段不停顿,但初始标记和重新标记阶段仍然需要 Stop-The-World。
候选人原话 B:"CMS 没有内存碎片问题。"
问题诊断:CMS 使用标记-清除算法,会产生内存碎片。长期运行后可能触发 Serial Old 的 Full GC(最长的停顿)。
1.3 标准回答
P5 级别:四个阶段
CMS 的四个阶段:
P6 级别:CMS 的问题
CMS 的三大问题:
1. 内存碎片:标记-清除不整理,产生大量内存碎片。导致的问题:
- 分配大对象时无法找到连续空间
- 触发 Full GC(Serial Old) 进行内存整理,停顿时间可能长达数秒
2. 浮动垃圾(Floating Garbage):
并发标记期间变成不可达的对象被称为"浮动垃圾",必须在下一次 GC 时才能清理。
3. 并发失败(Concurrent Mode Failure):
如果并发清除期间老年代满了(无法容纳浮动垃圾 + 新分配的对象),CMS 启动 Full GC(Serial Old):
降低 Concurrent Mode Failure 风险:
P7 级别:JDK 14 废弃的工程原因
CMS 被废弃的原因:
CMS 的代码复杂度极高(10 万行级别),维护成本大:
并发阶段与用户线程共享 CPU:CMS 的并发阶段消耗 CPU 资源,降低应用吞吐量
浮动垃圾问题无解:无法从根本上解决,只能推迟
碎片化问题:标记-清除算法无法解决碎片
JDK 的替代方案:
- JDK 9:G1 成为默认收集器
- JDK 11+:ZGC、Shenandoah 成为正式特性
- JDK 14:CMS 被标记为 deprecated
【面试官心理】 这道题我能问到 P7 级别,是因为 CMS 的废弃涉及了工程维护成本和 GC 技术演进的权衡。能说清 CMS 被废弃的工程原因的候选人说明他有技术视野。
1.4 追问升级
追问:CMS 的重新标记需要扫描什么?
重新标记需要扫描:
- 在并发标记期间新晋升到老年代的对象(之前在年轻代未被标记)
- 在并发标记期间新分配的对象(分配到老年代的对象)
- 在并发标记期间引用关系发生变化的对象
二、生产调优 🟡
2.1 CMS 参数配置
2.2 常见问题
面试加分点:能说出"CMS 的并发模式失败和 G1 的 Failure 模式非常相似,G1 借鉴了 CMS 的教训,在并发标记阶段更保守",说明他理解了 GC 技术的演进关系。
面试陷阱:被问到"CMS 的并发标记阶段,用户线程也在运行,会漏标记对象吗",很多人会说"会漏标记"。准确答案是:不会漏标记,因为并发标记阶段会使用三色标记算法,并且重新标记阶段会修正并发期间的引用变化(通过 Card Table)。