CMS核心目标是降低老年代GC停顿时间,适合延迟敏感服务,但易碎片化且JDK14+已移除;需搭配ParNew、固定堆大小、合理触发阈值及优化Remark等措施保障稳定性。

CMS 垃圾回收器的核心目标是降低老年代 GC 的停顿时间,适合对响应延迟敏感、CPU 资源较充裕的服务(如 API 网关、交易前置)。但它不移动对象,容易碎片化,且 JDK 9+ 已被标记为废弃,JDK 14+ 彻底移除。若仍在用 JDK 8 或部分 JDK 11 场景,需精准配置才能稳定低停顿。
基础启用与必要配套
CMS 只负责老年代,必须搭配 ParNew 新生代收集器使用,缺一不可:
- -XX:+UseConcMarkSweepGC:显式启用 CMS(JDK 8 必须加)
- -XX:+UseParNewGC:强制启用 ParNew;即使写了 CMS,JVM 也可能默认 fallback 到 SerialOld,此参数防退化
- -Xms3g -Xmx3g:堆大小固定,避免动态扩容触发额外 GC 或内存抖动(CMS 不适合超大堆,建议 ≤6GB)
- -Xmn1g:显式设新生代大小(比依赖 NewRatio 更可控),避免 Eden 过小导致 Minor GC 频繁、晋升压力大
控制触发时机,防并发模式失败
并发模式失败(Concurrent Mode Failure)是最危险的信号——CMS 没来得及清理完,老年代就满了,被迫退化为 Serial Old Full GC,STW 可达秒级。
- -XX:CMSInitiatingOccupancyFraction=65:设为 65(即老年代使用率达 65% 就启动 CMS),比默认 92% 更保守,预留空间消化浮动垃圾
- -XX:+UseCMSInitiatingOccupancyOnly:禁用 JVM 自适应调整,确保每次按设定阈值触发,行为可预测
- 配合 jstat -gc <pid> 1000 观察老年代占用增速,若每分钟晋升超 40MB,65% 仍可能偏高,可试调至 60%
压缩 STW 阶段耗时
CMS 全程只有 Initial Mark 和 Remark 两次 STW,其中 Remark 最易超时(常因跨代引用多、对象图复杂):
- -XX:+CMSScavengeBeforeRemark:Remark 前强制做一次 Minor GC,清掉新生代中已死对象,大幅减少需扫描的跨代引用
- -XX:+CMSParallelRemarkEnabled:启用多线程执行 Remark,尤其在多核机器上效果明显
- -XX:+CMSParallelInitialMarkEnabled:加速 Initial Mark(对堆 >2GB 有效)
- 若 Remark 仍持续 >200ms,检查是否在老年代存了大量频繁更新引用关系的缓存容器(如 ConcurrentHashMap + 定时刷新监听器列表)
缓解碎片与退化风险
CMS 用标记-清除,不整理内存,长期运行后碎片累积,可能导致大对象分配失败,直接触发 Full GC:
- -XX:+UseCMSCompactAtFullCollection:每次 Full GC 后执行内存压缩(代价是延长该次 FGC 时间,但换长期稳定)
- -XX:CMSFullGCsBeforeCompaction=1:每 1 次 Full GC 后就压缩一次,比“只在 Full GC 时才压”更平滑
- 生产环境预留 30%~40% 老年代空间作缓冲区,避免碎片 + 新晋升同时发生引发 Promotion Failed
- 对长周期服务,定期滚动重启比硬扛碎片更可靠;新项目建议直接迁移到 G1 或 ZGC


















