Concurrent Mode Failure发生时,JVM退化为Serial Old执行Full GC,因其是CMS官方指定的兜底收集器,采用标记-整理算法解决碎片问题,且逻辑简单、行为确定,被JDK 8及之前版本硬编码支持。

CMS 并发模式失败(Concurrent Mode Failure)发生时,若老年代因碎片过多而无法分配大对象,JVM 会立即中止 CMS 的并发流程,触发一次 Full GC,并回退到 Serial Old 收集器执行老年代回收。
回退机制的触发条件
并非所有 CMS 失败都走 Serial Old。只有满足以下任一情形,才会启用该后备方案:
- CMS 在并发标记或清理阶段发现老年代剩余连续空间不足,且无法满足当前晋升对象(尤其是大对象)的分配需求;
- Minor GC 后发生 Promotion Failed,同时老年代已无足够连续空间容纳晋升对象,CMS 来不及响应;
- CMS 并发收集被中断(如长时间停顿、系统资源紧张),且老年代占用率已超阈值(
-XX:CMSInitiatingOccupancyFraction),但尚未完成一轮完整周期。
为什么是 Serial Old 而不是其他收集器
Serial Old 是 CMS 的官方指定失败兜底方案,原因明确:
- 它采用 标记-整理(Mark-Compact)算法,能彻底解决内存碎片问题,确保大对象可分配;
- 它是单线程、STW 式收集器,逻辑简单、行为确定,适合作为“保底”路径,不依赖并发协调;
- 在 JDK 8 及之前,CMS + Serial Old 是 HotSpot 官方支持的组合,JVM 内部硬编码了该降级逻辑。
如何从日志确认已回退至 Serial Old
关键线索出现在 GC 日志末尾的收集器标识和行为特征:
- 出现
[CMS-concurrent-mark: ...] (concurrent mode failure)后,紧接着是[Full GC [Tenured: ...]或[CMS: ...] [Tenured: ...]; - 日志中明确包含
SerialOld或Serial MarkSweepCompact字样(取决于 JVM 版本); - GC 耗时显著拉长(常达数百毫秒至数秒),且
[Times: user=..., real=...]中 real 时间远大于 user,说明发生了长时间 STW; - 没有并发阶段时间统计(如
CMS-concurrent-preclean),也没有多线程 GC 线程数信息。
实际影响与应对建议
回退本身是保护性动作,但代价高昂:
- 整个堆被扫描,用户线程完全暂停,服务响应明显卡顿;
- Serial Old 单线程处理大堆时效率极低,可能引发雪崩式延迟;
- 频繁回退说明 CMS 已不适应当前负载,需尽快优化或迁移。
短期缓解可调低 -XX:CMSInitiatingOccupancyFraction(如设为 70),让 CMS 更早启动;长期应评估切换至 G1(自带压缩、抗碎片)或 ZGC,避免依赖这种高成本兜底机制。


















