CMS收集器仅负责老年代和元数据区回收,不参与年轻代回收;其核心是并发标记-清除,避免STW,但不压缩导致碎片;触发依赖老年代使用率或晋升失败,元数据区回收需显式启用参数。

CMS收集器只负责老年代和元数据区(JDK 1.8+ 的永久代替代者),不参与年轻代回收。它的回收逻辑围绕“并发低停顿”设计,核心是分阶段标记存活对象,再清理未标记的垃圾,全程避开对新生代的干预。
老年代回收是CMS的唯一主责
CMS启动后,所有工作都聚焦于老年代空间:
- 触发条件依赖老年代使用率,默认达92%就启动回收(可通过-XX:CMSInitiatingOccupancyFraction调整);
- 若Minor GC后发生晋升担保失败(即老年代剩余空间不足以容纳待晋升对象),也会立即触发CMS回收;
- 回收过程不会触碰Eden、Survivor等年轻代区域,这些区域仍由ParNew或Serial等年轻代收集器独立处理。
元数据区回收需显式启用
从JDK 1.8起,永久代被元数据区(Metaspace)取代。CMS默认不回收该区域,必须配合以下参数才生效:
- -XX:+CMSClassUnloadingEnabled:允许卸载无用类;
- 此时CMS会在重新标记阶段扫描类加载器引用关系,识别并回收已无实例且无强引用的类元数据;
- 元数据区的回收阈值由-XX:CMSInitiatingPermOccupancyFraction控制(注意参数名中仍含“Perm”,但实际作用于Metaspace)。
不回收年轻代,也不做压缩整理
CMS的设计定位决定它主动规避两类操作:
- 完全跳过年轻代——既不扫描Eden/Survivor中的对象,也不参与对象晋升决策,仅被动接收晋升来的对象;
- 采用标记-清除算法,不移动存活对象,因此不执行内存压缩(Compact)。这导致长期运行后易产生碎片,大对象分配可能失败并退化为Full GC;
- 如需缓解碎片,只能靠-XX:+UseCMSCompactAtFullCollection在Full GC后强制整理,但这不属于CMS本体流程。
回收不是“等满了再清”,而是提前预判
CMS属于“前瞻性”收集器,不能等到老年代彻底填满才动作:
- 若等到100%占用才启动,必然因来不及完成而失败,触发STW更久的Serial Old兜底回收;
- 因此它依赖后台线程(ConcurrentMarkSweepThread)每2秒轮询一次内存状态,结合历史GC数据动态判断是否该启动;
- 建议线上环境加上-XX:+UseCMSInitiatingOccupancyOnly,禁用动态预测,让触发行为完全由设定阈值控制,便于监控与调优。


















