三色标记法是并发垃圾回收中保障标记安全的核心机制,用白(待考察)、灰(正处理)、黑(已扫描)三色模拟可达性演进,通过灰色缓冲状态与写屏障协同维护三色不变式,防止漏标。

三色标记法是标记-清除垃圾回收中用于保证并发标记安全的核心机制,本质是用颜色状态模拟对象的可达性演进过程,避免漏标(即本该存活的对象被错误回收)。
白色:暂定为“待考察”对象
初始时所有对象都标记为白色,表示尚未被 GC 探查过,也不确定是否可达。它不是“死亡”,而是“未确认”。随着标记推进,白色对象会逐步被染成灰色或黑色——一旦被根对象直接引用,就进入灰色;若其所有引用对象都已处理完毕,则升为黑色。
灰色:正在处理中的活跃对象
灰色对象是已发现、但其引用的子对象尚未全部扫描完成的中间状态。GC 线程从灰色集合中取出一个对象,遍历它的字段,把所有指向白色对象的引用改为灰色(即加入待处理队列),自身再转为黑色。这一步必须原子执行,否则并发修改可能导致漏标。
- 典型操作:读取对象字段 → 发现白色引用 → 将其压入灰色队列 → 当前对象变黑
- 关键约束:灰色对象不能被用户线程修改其引用关系,否则需配合写屏障(如增量更新或原始快照)来拦截并补标
黑色:已完全扫描的安全对象
黑色对象表示其自身及所有可达对象都已被标记,不再参与后续扫描。但它可能成为漏标源头——如果用户线程在它变黑后,又给它新增了一个对白色对象的引用,而该白色对象还未被其他灰色对象发现,就会遗漏。
- 这就是为什么三色不变式(Tri-color invariant)必须成立:黑色对象不能指向白色对象
- 实际中靠写屏障打破该违反:当黑色对象新增白色引用时,强制将该白色对象重新标记为灰色(增量更新),或记录旧引用快照供后续重新扫描(SATB)
为什么需要三色而非二色
纯黑白标记在并发场景下无法区分“尚未扫描”和“确实不可达”,容易因用户线程与 GC 线程竞争导致误回收。三色通过灰色作为缓冲状态,明确划分“已发现但未完成”这一中间阶段,使写屏障能精准干预异常引用变更,从而在不暂停应用的前提下维持标记准确性。
不复杂但容易忽略的是:颜色本身不存储在对象头里,而是由 GC 控制器维护的逻辑状态,常映射为位图或独立集合;真正起作用的是状态迁移规则与配套的屏障策略。

















