JVM垃圾回收标记算法以可达性分析为逻辑起点,通过三色标记实现并发,依赖写/读屏障保障安全,并随分代到区域化演进提升效率。

JVM 垃圾回收中的标记算法,核心目标是准确、高效、低干扰地识别存活对象。它不是孤立存在的技术点,而是随着停顿控制、并发能力、内存规模等需求不断演进的底层机制。从一次性全量扫描,到支持并发标记的三色状态机,再到面向大堆与亚毫秒延迟的硬件辅助设计,标记方式的每一次升级,都直接决定了 GC 的可用性边界。
可达性分析:标记的逻辑起点
所有现代 JVM 标记算法都基于“可达性分析”,而非引用计数——后者因无法处理循环引用而被弃用。GC Roots(如线程栈帧局部变量、静态字段、JNI 引用等)作为起点,通过引用链向外遍历。只要能从 Roots 到达,对象即为存活;否则视为垃圾。这个原则自 JDK 1.0 起未变,但“如何遍历”和“何时遍历”持续进化。
三色标记:并发标记的基石
传统标记-清除需全程 STW,而三色标记通过引入中间状态,把标记过程拆解为可暂停、可恢复的增量步骤:
- 白色:初始状态,表示尚未访问,也未确认是否存活
- 灰色:已标记,但其引用的对象尚未全部扫描(它是待处理队列的入口)
- 黑色:已完全扫描,其所有直接/间接引用均已被纳入标记范围
标记启动时,所有 Roots 直接引用的对象入灰;灰对象出队后,将其引用的对象入灰,自身转黑;灰集为空即标记完成。关键在于:应用线程与 GC 线程并发执行时,若对象引用关系变更,可能破坏“黑→白”不可达的约束,导致漏标。CMS 采用写屏障(Incremental Update)在新增引用时将目标对象重新标灰;G1 使用 SATB(Snapshot-At-The-Beginning)在删除引用前记录快照,确保不遗漏。
增量更新与读写屏障:保障并发安全
三色标记本身不解决并发修改问题,真正让它落地的是配套的屏障机制:
- 写屏障(Write Barrier):在每次对象引用赋值时插入轻量级检查逻辑。CMS 在写入新引用时触发,防止黑对象指向白对象;ZGC 和 Shenandoah 则使用更精细的着色指针 + 内存屏障,在对象加载或存储时捕获状态变化
- 读屏障(Read Barrier):ZGC 和 Shenandoah 在对象读取时介入,用于实现“染色指针”和并发重映射。例如 ZGC 将元数据(标记位、重定位状态)直接编码进 64 位指针的高几位,读取时自动解析并触发必要动作,避免额外内存访问开销
这些屏障让标记不再依赖全局暂停,而是把一致性维护下沉到单次内存操作粒度,是低延迟 GC 的关键支撑。
从分代到区域化:标记范围的动态聚焦
早期 Serial、Parallel GC 对整个年轻代或老年代做统一标记,效率随堆增大而下降。G1 引入 Region 概念,将堆划分为固定大小块(1–32MB),标记阶段只追踪跨 Region 引用(Remembered Set),混合 GC 时优先标记垃圾最多的 Region;ZGC 进一步按页(Page)组织,结合着色指针实现几乎无成本的并发标记——它不维护传统意义上的“标记位数组”,而是通过指针颜色直接反映对象状态,标记过程本质是遍历 Root 并翻转相关指针颜色,无需额外标记空间。

















