HotSpot JVM弃用Mark Word的11标志位做GC标记,因缓存污染、并发同步开销大及与锁机制冲突;现代GC统一采用独立位图映射堆内存,通过写屏障+三色标记解决并发漏标问题。

标记清除阶段不会直接通过对象头的 Mark Word 来做 GC 标记,所以不存在“Mark Word 标记位的物理读写并发冲突”这个问题。
为什么不用 Mark Word 做 GC 标记?
HotSpot JVM 早在多年以前就弃用了在对象头中复用 Mark Word 的两个比特位(即标志位为 11)来表示 GC 标记状态的做法。原因很明确:
- 缓存污染严重:频繁修改每个对象的对象头,会破坏 CPU 缓存行局部性,大幅降低标记吞吐;
- 并发安全成本高:多个 GC 线程同时修改不同对象的 Mark Word,需大量 CAS 或锁同步,反而拖慢标记速度;
- 与锁机制冲突:Mark Word 已被用于存储锁状态(偏向锁 ID、轻量级锁指针等),GC 标记和锁升级/降级可能同时竞争同一字段。
现代 JVM 实际怎么标记?
主流 GC(如 G1、ZGC、Shenandoah、Parallel GC)统一采用独立位图(Bitmap)+ 堆内存分块映射的方式:
- 为整个堆维护一块只读/可写位图(BitSet),每个 bit 对应一个对象或一个固定大小内存单元(如 64 字节对齐块);
- 标记时,GC 线程只操作位图——设置对应 bit 为 1,完全不碰对象头;
- 位图本身按页划分,支持多线程并行写入(如 G1 使用 per-region bitmap,ZGC 使用 multi-page bitmap),天然规避对象头粒度的并发写冲突。
那 Mark Word 里 “11” 标志位还存在吗?
存在,但仅作为历史兼容保留字段,实际 GC 过程中不依赖它:
- 某些低配 GC(如 Serial、CMS 的早期版本)曾短暂使用过该标志位,但已淘汰;
- 当前 HotSpot 源码中,该字段仍保留在 Mark Word 定义里,但标记逻辑完全绕开它;
- 若你用 JOL(Java Object Layout)工具查看对象头,看到 GC 标记位为 11,大概率是调试模式下人工模拟,或极老版本 JVM 的残留行为。
真正要防的并发问题是什么?
不是 Mark Word 写冲突,而是用户线程在并发标记过程中修改引用关系导致的漏标(Floating Garbage 或 Incorrect Collection)。解决方案是:
- 三色标记 + SATB(G1)或 Brooks Pointer(ZGC):在引用被修改前捕获快照;
-
写屏障(Write Barrier):在赋值语句(如
obj.field = newObj)前后插入检查逻辑,把被覆盖的旧引用加入灰色集合; - 初始标记和重新标记阶段 STW:确保根集合和脏卡页被完整扫描,兜底修正并发偏差。


















