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。
别急,先让缓存热一下。