cms通过写屏障实时标记新存活对象并加入待扫描队列,结合卡表限定扫描范围,避免误清除且不依赖锁或应用层同步,浮动垃圾属主动容忍设计。

CMS并发清理阶段本身不处理引用竞争,它规避的是“误清除存活对象”这一致命风险——靠的是写屏障(Write Barrier)机制,而非锁或同步。
写屏障拦截所有引用写入操作
当应用线程执行类似 objA.field = objB 这类修改老年代对象字段的操作时,JVM会触发写屏障。它不是简单记录,而是实时检查被赋值对象 objB 的标记状态:
- 若
objB已被标记为存活(黑色或灰色),直接放行,无需干预 - 若
objB当前未被标记(白色),说明它可能被漏标或正变为新存活对象,写屏障立即将其重新标记为存活,并加入“待重新扫描队列”
这个过程发生在毫秒级,完全由JVM底层保障,开发者无需编码参与。
浮动垃圾是设计容忍,不是数据错乱
并发清除阶段确实会产生新垃圾(如刚创建又断引用的对象),但这些“浮动垃圾”不会被本轮清除——CMS只按重新标记阶段确认的垃圾名单清理。这看似“不及时”,实则是主动取舍:
- 避免在清除过程中反复扫描、重标记,防止STW时间失控
- 浮动垃圾仅影响内存使用率,不影响对象语义和引用正确性
- 极端情况下触发 Concurrent Mode Failure,降级为 Full GC,仍是安全兜底
卡表机制限定扫描范围,减少干扰面
预清理和并发清除都依赖卡表(Card Table):只有被写屏障标记为“脏”的内存页(卡)才会被扫描。这意味着:
- 不扫描全堆,大幅降低GC线程与应用线程的内存访问冲突概率
- 脏卡数量可控,间接限制了需通过写屏障校验的引用变更总量
- 卡表本身由JVM原子维护,无竞态风险
不依赖锁,也不靠应用层同步
CMS的设计哲学是“最小化用户干预”。它不假设业务代码加锁,也不要求开发者用 synchronized 或 ConcurrentHashMap 来配合GC:
- 写屏障是JVM指令级插入,比任何Java层锁都更底层、更轻量
- 卡表更新使用原子CPU指令(如 x86 的
LOCK前缀),无锁实现 - 并发清除线程只读取已确定的垃圾列表,全程无写共享状态
真正需要开发者关注的,是避免高频修改老年代大对象(如反复 put 到老年代的 ConcurrentHashMap),因为这会持续产生脏卡,加重写屏障和预清理负担——这不是引用竞争问题,而是GC效率问题。











