CMS发生Concurrent Mode Failure时,JVM立即中止并发周期并强制切换至Serial Old执行Full GC,因其采用标记-整理算法可解决碎片问题,行为确定且被JDK 8及之前版本硬编码支持。

CMS 发生 Concurrent Mode Failure(CMF)时,JVM 不会尝试“重启”或“重试”CMS 流程,而是立即中止当前并发周期,触发一次 Full GC,并强制切换至 Serial Old 收集器执行。这不是权宜之计,而是 HotSpot 在 JDK 8 及之前版本中硬编码的、唯一被官方支持的兜底路径。
退化不是随机选择,而是设计锁定
CMS 的备用 Full GC 收集器只能是 Serial Old,原因很明确:
- 算法兼容性要求:Serial Old 使用标记-整理(Mark-Compact),能彻底解决 CMS 长期运行积累的内存碎片问题,确保大对象可分配;而 Parallel Old 虽为多线程,但采用标记-整理与 CMS 的并发逻辑存在内部冲突,HotSpot 明确不支持二者组合。
- 行为确定性优先:CMF 发生时,老年代已濒临耗尽,系统处于内存临界状态。单线程执行避免了多线程竞争、引用更新错乱等风险,保障回收过程稳定可控。
- 实现轻量且可靠:Serial Old 无并发协调开销,代码路径短,STW 行为可预测,适合作为“保底通道”,无需额外初始化或资源协商。
触发退化的典型场景
并非所有老年代紧张都会导致 CMF 退化,只有满足以下任一条件,JVM 才会激活 Serial Old:
- CMS 在并发标记或并发清理阶段检测到:剩余连续空间 < 当前待晋升对象(如大对象)大小;
- Minor GC 后发生 Promotion Failed,且此时老年代已无足够连续空间容纳晋升对象,CMS 来不及响应;
- CMS 并发周期被中断(如长时间 STW、系统资源严重不足),同时老年代占用率已超 -XX:CMSInitiatingOccupancyFraction 设定阈值,但尚未完成一轮完整回收。
如何从日志确认已退化
关键线索集中在 GC 日志末尾的行为特征:
- 出现 concurrent mode failure 或 Concurrent Mode Failure 字样,紧随其后是 Full GC 或 GC pause (full),Cause 标注为 Allocation Failure 或 CMF;
- 没有 CMS 并发阶段时间统计(如 CMS-concurrent-mark、CMS-concurrent-sweep);
- GC 耗时显著拉长(常达数百毫秒至数秒),real 时间远大于 user 时间,说明是单线程 STW;
- 日志中不会出现并行线程数(如 [ParNew: ...] [CMS: ...] 中的线程标识),也无 ParallelOld 相关字样。
这不是故障,而是信号
CMF 退化本身不是 JVM Bug,而是 CMS 设计边界被突破的明确提示:当前负载节奏已超出 CMS 并发回收能力。它暴露的是晋升速率突增、浮动垃圾失控、碎片累积或触发阈值设置不当等问题。调优重点不在阻止退化发生,而在于让 CMS 有足够缓冲时间完成工作——提前启动、减少晋升压力、控制临时对象生命周期,才是治本之策。


















