cms并发失败时jvm退化为serial old执行full gc,因其采用标记-整理算法解决碎片问题,且是jdk 8及之前硬编码的单线程stw兜底方案。

Serial Old 和 CMS 的 Full GC 是两类性质完全不同的老年代回收行为,不能简单比“快慢”,关键要看场景目标:一个是单线程、STW 全停顿的兜底方案,另一个是并发设计、以降低停顿为目标的专用收集器——但 CMS 的 Full GC 本身恰恰说明它已失败,此时触发的正是 Serial Old。
Serial Old 是 CMS 失败后的兜底机制
CMS 本身不执行传统意义上的 Full GC。当 CMS 并发收集失败(如并发模式失败 Concurrent Mode Failure、晋升失败 Promotion Failure 或永久代/元空间不足),JVM 会立即中止 CMS 流程,退回到 Serial Old 收集器执行一次完整的、单线程的老年代标记-整理回收。这个过程就是常说的 “CMS 触发了 Full GC”,但实际执行者是 Serial Old。
- 该过程全程 STW,暂停时间取决于老年代大小和存活对象数量,可能长达数秒甚至更久
- 使用标记-整理算法,回收后内存连续,无碎片
- 单线程运行,CPU 利用率低,但避免了多线程同步开销
CMS 本身不追求 Full GC,而是尽力避免它
CMS 的设计哲学是“少停顿、多并发”。它只对老年代做并发标记-清除,不压缩、不整理,因此:
- 正常运行时只有两次短暂 STW(初始标记、重新标记),每次通常几毫秒到几十毫秒
- 并发清除阶段用户线程照常运行,但会产生浮动垃圾(并发期间新产生的死亡对象)
- 长期运行后老年代易产生内存碎片,可能触发 Promotion Failure,进而引发 Serial Old Full GC
性能对比的核心维度
不是“谁更快”,而是“在什么前提下发生、代价是什么”:
- 暂停时间:CMS 正常周期远低于 Serial Old Full GC;但一旦退化为 Serial Old,暂停时间会陡增一个数量级
- 吞吐量:Serial Old 全程独占 CPU,但耗时长;CMS 占用部分 CPU 做并发工作,整体吞吐受干扰较小(除非并发失败频发)
- 内存效率:Serial Old 整理后无碎片;CMS 清除后留碎片,可能提前触发 Full GC
- 稳定性:频繁 CMS 失败 → 频繁 Serial Old Full GC → 应用响应雪崩;这是典型的配置失当信号
如何减少 Serial Old Full GC 的发生
根本思路是让 CMS 尽量不失败:
- 调大老年代空间(-Xmx/-Xms),降低触发并发收集的阈值(-XX:CMSInitiatingOccupancyFraction)
- 预留足够浮动垃圾空间,例如设置 -XX:CMSInitiatingOccupancyFraction=70(默认约92%,太晚)
- 避免新生代过快晋升,调优 Young GC 频率与对象晋升年龄(-XX:MaxTenuringThreshold)
- 监控 CMS 失败日志:出现 “concurrent mode failure” 或 “promotion failed” 就是明确预警
Serial Old Full GC 不是 CMS 的一种模式,而是它的失效结果。真正有意义的对比,是在 CMS 正常并发周期 vs Serial Old 兜底回收之间划清界限——前者是主动控制的低延迟策略,后者是被动承受的高成本补救。











