浮动垃圾是cms并发标记/清理阶段用户线程持续运行产生的新垃圾,无法当次回收,积累后直接触发concurrent mode failure,迫使jvm退化为serial old执行full gc。

CMS 的“浮动垃圾”和“并发模式失败”不是孤立现象,而是紧密耦合的因果链:浮动垃圾积累直接触发并发模式失败,而后者强制 JVM 退化为 Serial Old 收集器执行 Full GC,带来秒级停顿。根本原因在于 CMS 的并发设计与内存管理机制存在天然矛盾。
浮动垃圾是怎么产生的
CMS 在并发标记和并发清理阶段,用户线程持续运行,不断创建新对象、丢弃旧引用。这些在标记结束之后才产生的垃圾,CMS 无法在本轮回收中识别和清除——它们就是“浮动垃圾”。它不参与本次 GC 的标记过程,却实实在在占用了老年代空间。
- 例如:一次 CMS 并发清理耗时 200ms,在这期间用户线程分配了 80MB 新对象,其中 60MB 很快变为垃圾,这部分就是浮动垃圾
- 浮动垃圾不会立即被回收,必须等到下一轮 GC 才有机会处理
- 它和新生代晋升对象一起,共同挤压老年代剩余可用空间
并发模式失败如何被浮动垃圾引爆
CMS 预留了一定老年代空间(默认占用率 ≥92% 时启动)来容纳浮动垃圾和预期晋升量。一旦实际浮动垃圾 + 晋升对象总量超过预留余量,就会触发 Concurrent Mode Failure。
- 公式本质是:老年代剩余空间 < 预期晋升量 + 当前浮动垃圾量
- 常见诱因包括:CMSInitiatingOccupancyFraction 设置过高(如调到 95%)、业务突发流量导致对象分配激增、Young GC 频繁且晋升率升高
- 此时 CMS 已无法安全继续并发流程,必须中止并切换回收策略
为什么失败后一定是单线程 Full GC
发生 Concurrent Mode Failure 时,JVM 不会尝试用 Parallel Old 或其他并发收集器接管,而是直接启用 Serial Old —— 这是设计上的主动降级,而非能力缺失。
- Serial Old 是标记-整理算法,能压缩碎片、确保大对象分配成功,而 CMS 的标记-清除无法解决碎片问题
- 多线程 GC 在资源已紧张(CMS 正在争抢 CPU)时介入,可能加剧系统不稳;单线程更可控、无同步开销
- 它是兜底机制:不求快,但求稳、可预测、必成功
不解决会怎样
若放任浮动垃圾持续积累、并发模式失败反复发生,系统将陷入恶性循环:Full GC 越来越频繁 → STW 时间叠加增长 → 响应延迟飙升 → 用户请求超时或失败。尤其在高吞吐、低延迟场景(如交易、实时接口),这种不可控停顿等同于服务降级。











