三色标记法是并发可达性分析的逻辑骨架,用白(未触达)、灰(正处理)、黑(已确认)三种状态编码对象扫描进度;黑色对象不可直连白色对象,否则漏标,cms用增量更新、g1用satb写屏障机制修正。

三色标记法不是颜色游戏,而是并发可达性分析的逻辑骨架。它用白、灰、黑三种状态,把对象在扫描过程中的“访问进度”显式编码出来,让 GC 线程和用户线程能安全共存。
白色:未触达的待判定对象
初始时所有对象都是白色——不代表“一定是垃圾”,只代表“还没被 GC 看过”。标记阶段结束时仍为白色,才真正判定为不可达、可回收。注意:新分配的对象默认直接进白色集合,不参与本轮标记;部分回收器(如 G1)会将它们视作隐式黑色,避免反复扫描。
灰色:正在处理的中间节点
灰色是扫描推进的“活口”。一个对象变成灰色,意味着它已被 GC 访问,但它的字段还没全扫完——比如某个对象有 3 个引用字段,只处理了前 2 个,第 3 个还没读,它就卡在灰色。GC 线程持续从灰色集合取对象,遍历其引用,把新发现的未标记对象涂灰,再把自己涂黑。它是整个并发标记的驱动引擎。
黑色:已确认安全的终结点
黑色对象表示“本体 + 所有直接引用”都已完成检查,且这些引用所指向的对象至少已被标记为灰或黑。关键约束是:黑色对象不能直接指向白色对象。一旦出现黑→白引用,就破坏了三色不变式,可能漏标——而这正是并发修改引发问题的根源。所以 CMS 用增量更新(把新黑→白引用记下来,后续重扫),G1 用原始快照(在删灰→白引用前,先快照记录该引用,确保不丢失)。
扫描链路如何在并发中保持正确
实际扫描不是单线程深度遍历,而是工作窃取式并行推进:
- 初始标记阶段:STW,仅将 GC Roots 直接引用的对象涂灰(极快)
- 并发标记阶段:GC 线程从灰色队列取对象,涂黑自身,将其未标记的子对象涂灰;用户线程同时修改引用
- 写屏障介入:每当用户线程执行
obj.field = newObj或obj.field = null,JVM 插入写屏障逻辑,按策略记录变更(CMS 记黑→白,G1 记灰→白删除) - 重新标记阶段:STW,回溯写屏障记录的“危险引用”,以对应对象为根补扫,修正漏标
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











