浮动垃圾是cms在并发标记完成后、并发清理阶段新产生的未标记垃圾对象,无法在本轮回收,需待下一轮gc根据其是否仍不可达来决定是否回收。

CMS(Concurrent Mark-Sweep)收集器在并发清理阶段确实会产生“浮动垃圾”(Floating Garbage),这是其并发执行模型固有的现象,无法完全避免,但可通过合理配置与监控加以控制。
什么是浮动垃圾
浮动垃圾指在 CMS 并发标记(Concurrent Mark)完成后、并发清理(Concurrent Sweep)开始前或进行中,新产生的、本应被回收但未被本轮 GC 捕获的垃圾对象。原因在于:CMS 的标记阶段是“并发”的,用户线程持续运行,可能在标记结束后立即分配并丢弃对象,而这些对象不会被本次清理扫描到。
浮动垃圾的处理策略
浮动垃圾本身不参与本轮清理,只能等待下一次 GC 周期处理。关键不是“清除它”,而是防止其累积引发失败:
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
-
预留足够老年代空间:通过
-XX:CMSInitiatingOccupancyFraction提前触发 CMS(例如设为 70~75),确保有足够空闲空间容纳浮动垃圾,避免并发模式失败(Concurrent Mode Failure)。 -
启用担保机制:当并发清理来不及处理或浮动垃圾过多导致老年代满时,JVM 会降级为 Serial Old 全停顿回收。可通过
-XX:+UseCMSCompactAtFullCollection和-XX:CMSFullGCsBeforeCompaction减少碎片,降低 Full GC 频率。 -
监控与调优:关注 GC 日志中的
concurrent mode failure和promotion failed;使用-XX:+PrintGCDetails -XX:+PrintGCTimeStamps分析浮动垃圾增长趋势,结合jstat -gc观察老年代使用率波动。
为什么不能在并发清理中实时处理浮动垃圾
CMS 的并发清理阶段只清理“已标记为不可达”的对象,不再重新扫描整个堆。重新标记(Remark)已在并发标记后完成,且 Remark 是 STW 阶段,必须尽快结束。若在清理阶段动态追加新垃圾,需再次遍历引用关系,违背 CMS “低延迟”设计目标,也极易引发更长的停顿或死锁风险。
替代方案参考
若浮动垃圾问题频繁(如高分配率 + 大老年代),说明 CMS 已难以适应场景。可考虑:
- 升级到 G1 收集器,通过增量式标记和混合 GC 主动控制老年代回收节奏;
- 评估 ZGC 或 Shenandoah,它们通过读屏障和并发转移,在极低停顿下更彻底地处理并发产生的垃圾。
CMS 已在 JDK 9 中被标记为废弃,JDK 14 正式移除。当前新项目不建议选用,存量系统需重点监控浮动垃圾引发的并发模式失败频率,作为迁移收集器的重要依据。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










