← 每日面试题 学习看板

什么是三色标记算法?

面试题/00java/03JVM/04垃圾回收(GC)基础/什么是三色标记算法?.md

面试记录 2026-09-21

题目:什么是三色标记算法?

难度:low

标签:jvm/gc, general/knowledge, difficulty/low

评分:⭐☆☆☆☆(1/5)

我的回答

这个所谓三色标记算法,其实是在 CMS 的垃圾回收器阶段开发使用的。其核心作用是标记对象的存活方式。如果一个对象初始存活创建,做一个标记。当这个对象它首次被访问的时候,但是没有确定它最终的结果是存活还是不存活的时候,做一个标记,应该是灰色吧。最开始是黑色,然后是灰色,然后是白色。如果这个对象标记完确认不能存活,就标记为黑色。应该是白色,初始默认是黑色,标记为白色。这样就可以判定这个对象是否还存活,是否有价值。如果一个对象发生了引用的变化,它会重新重置。整个链路过程就是初始为黑,然后扫描,扫描到它,它如果是没有引用,跟直达的引用,就把它标记为黑,标标记为白色。如果它还有引用,就标记为灰色。最终确认这些对象所有对象的状态,然后对统一的标记完没有引用的颜色的,没有引用的对象进行统一的回收,就是三色标记算法。

点评

优点:

不足:

补充:

完整讲解

第一部分:知识重点剖析

核心考点定位:考察三色标记的严格定义+并发场景的内存安全问题+修复机制(写屏障/读屏障)。

知识点拆解:

  1. 三色严格定义(HotSpot 采用)
  1. 算法流程
   1. 所有对象初始为白色
   2. GC Roots 全部染黑
   3. 取一个黑节点,扫描其引用:
      - 引用的对象若为白 → 染灰、加入工作队列
      - 该黑节点所有引用扫描完 → 完成
   4. 从工作队列取灰节点:
      - 扫描其引用,白→灰、入队
      - 所有引用扫描完 → 染黑
   5. 工作队列为空时结束
   6. 剩余白色对象 = 垃圾,回收

不变式(正确性条件):

  1. 并发场景的两大问题(重点!)

三色标记的核心动机是并发标记——让 GC 与用户线程并发扫描,减少 STW。但并发带来两个引用变动:

准确表述:

  1. 两种修复方案
修复方案屏障类型使用者核心思想
写屏障Write BarrierCMS、G1、ZGC(经典)修复"黑指白":对象引用变白 → 父对象重染灰
读屏障Read/Load BarrierShenandoah、ZGC(现代)修复"白指黑":读指针时检查有效性,无效则重新标记
  1. ZGC 的启示
  1. CMS 的具体流程中的三色标记

第二部分:考察方向与延伸递进

考察方向:

延伸递进面试题:

  1. 三色标记的"对象消失"问题具体怎么走通?
  1. 写屏障具体怎么处理?
  1. 为什么 ZGC 从写屏障转向读屏障?
  1. Shenandoah 的 Brooks 转发是什么?
  1. 三色标记和可达性分析的关系?

第三部分:面试者参考回答(300-600 字口语化)

面试官您好,三色标记算法是并发 GC 的核心算法,让 GC 扫描和用户线程并发运行,减少 STW。

三色严格定义(HotSpot 采用):

算法流程:GC Roots 全部染黑 → 取灰节点扫描子节点,白节点变灰入队,灰节点扫描完变黑 → 工作队列为空时结束 → 剩余白色对象就是垃圾,回收。

核心思想:白色 = 潜在垃圾,黑色 = 确定存活,灰色 = 中间态。

并发带来的两个内存安全问题:

  1. 对象消失(漏回收):黑节点 X 引用白节点 Y → 扫描完成断链 X→Y → 用户线程创建黑节点 Z 引用 Y → 此时 Y 从未被访问保持白,被误回收。这违反"黑不能指白"规则。
  2. 对象复活(误回收):白节点变黑后仍被断链,导致实际存活的对象被标成白。这违反"灰不能指黑"规则。

两种修复方案:

为什么 ZGC 从写屏障转向读屏障? 写屏障每次赋值都触发,影响吞吐;读屏障只在读取指针时检查,对代码侵入小。ZGC 配合多映射(同一虚拟地址映射多物理地址,移动对象改映射而非改引用)实现 STW <1ms。

CMS 中的三色标记:Initial Mark(STW)染黑 GC Roots → Concurrent Mark 并发三色扫描 → Remark(STW)靠写屏障追踪并发期间的引用变动。

一句话总结:三色标记是可达性分析的并发实现——本质都是从 GC Roots 遍历,但通过三色状态管理并发下的引用变动,靠写屏障或读屏障保证内存安全。