浮动垃圾不会在本轮cms回收中清除,需待下一轮gc时根据其是否仍不可达来决定是否回收;它由并发标记完成后新产生的未标记垃圾对象构成,受程序运行和引用变化影响。

CMS(Concurrent Mark-Sweep)收集器在并发清理阶段产生的浮动垃圾(Floating Garbage),不会在本轮回收中被清除,而是留待下一次GC周期处理——但前提是它们在下次标记开始前已变为不可达对象。
浮动垃圾的产生原因
浮动垃圾指在CMS并发标记(Concurrent Mark)完成后、并发清理(Concurrent Sweep)过程中新产生的、且未被本轮标记覆盖的垃圾对象。典型场景包括:
- 用户线程在并发标记结束后、重新标记(Remark)之前继续运行,创建新对象并丢弃引用;
- 并发清理阶段,部分对象刚被程序释放,但尚未被清理线程扫描到;
- 重新标记阶段虽会修正部分漏标,但无法覆盖所有并发修改(尤其涉及跨代引用或写后读等复杂情况)。
下一次GC如何回收这些浮动垃圾
浮动垃圾能否被下一轮CMS回收,取决于它在下一轮初始标记(Initial Mark)触发时是否仍不可达:
- 如果该对象在下一轮GC开始前已被程序完全丢弃引用(即无任何GC Roots可达路径),则会在新一轮并发标记中被识别为“未标记”,最终在后续清理阶段回收;
- 若该对象在下一轮GC启动前又被其他活跃对象重新引用(例如放入缓存、静态集合等),则不再属于垃圾,自然不被回收;
- CMS本身不压缩,所以浮动垃圾仅靠标记-清除逻辑处理,不会因内存碎片导致遗漏——只要标记准确,清理阶段就会归还其占用空间。
实际影响与应对建议
浮动垃圾本身是CMS并发设计的固有折衷,无法完全避免,但可通过以下方式降低其影响:
-
控制并发周期频率:通过调小
-XX:CMSInitiatingOccupancyFraction提前触发CMS,缩短浮动垃圾驻留时间; - 减少并发期大对象分配:避免在CMS运行期间频繁创建长生命周期对象,降低浮动垃圾规模;
- 关注晋升失败与并发模式失败:若浮动垃圾积累过多,配合老年代空间不足,易引发 Concurrent Mode Failure,此时JVM会退化为Serial Old进行Full GC——这反而能一次性清理所有浮动垃圾,但停顿显著增大。
浮动垃圾不是bug,而是CMS为降低STW时间所付出的代价。它的回收不依赖特殊机制,只遵循标准标记逻辑,关键在于下一轮GC开始时的对象可达性状态。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











