Skip to content

CMS GC

CMS(Concurrent Mark Sweep)是面向低停顿的老年代回收器。它通过并发标记和并发清除减少应用停顿,但会带来 CPU 竞争、浮动垃圾和内存碎片问题。CMS 已属于老系统维护知识,新项目通常不再选择它。

定位

维度说明
核心目标降低老年代回收停顿
执行方式初始标记和重新标记 STW,其余阶段并发
典型组合ParNew + CMS
主要问题内存碎片、浮动垃圾、并发失败
新项目建议优先 G1、ZGC、Shenandoah

工作阶段

text
初始标记(STW) -> 并发标记 -> 重新标记(STW) -> 并发清除 -> 重置

初始标记

短暂停顿,标记 GC Roots 直接可达对象。

并发标记

GC 线程和应用线程一起运行,沿引用链继续标记对象。

重新标记

再次短暂停顿,修正并发期间应用线程修改引用造成的变化。

并发清除

回收不可达对象,但不做压缩整理,因此可能产生内存碎片。

常见问题

Concurrent Mode Failure

CMS 并发回收还没完成,老年代就无法继续分配,JVM 退回更重的 Full GC。

处理方向:

  • 提前触发 CMS。
  • 增大老年代空间。
  • 降低对象晋升速度。
  • 评估迁移到 G1。

内存碎片

CMS 使用标记-清除,不压缩对象。老年代总空闲空间够,但连续空间不够时,大对象仍可能分配失败。

处理方向:

  • 减少大对象分配。
  • 观察 Full GC 和压缩行为。
  • 迁移到带整理或分区能力的回收器。

CPU 竞争

并发阶段 GC 线程和应用线程同时运行,可能抢 CPU。

排查:

bash
top -H -p <pid>
jstat -gcutil <pid> 1000

老系统参数识别

老服务中可能看到:

bash
-XX:+UseConcMarkSweepGC
-XX:CMSInitiatingOccupancyFraction=70
-XX:+UseCMSInitiatingOccupancyOnly

这些参数不适合直接迁移到新 JDK。升级时应先确认 JDK 支持情况,再设计 GC 迁移方案。

迁移建议

当前问题迁移方向
CMS 碎片导致 Full GCG1
停顿仍无法满足ZGC / Shenandoah
系统主要是吞吐型Parallel 或 G1
JDK 版本较老先拆分 JDK 升级和 GC 迁移风险

迁移前后对比:

  • 吞吐量。
  • P95/P99/P999 延迟。
  • GC 总 CPU。
  • Full GC 次数。
  • 堆和 RSS。
别急,先让缓存热一下。