标记-清除算法的标记过程本质是通过三色标记法从gc roots出发遍历可达对象:白色表未访问、灰色表待扫描、黑色表已扫描完成;标记结束时仍为白色的对象即为垃圾,该过程仅记录状态、不移动内存。

标记-清除算法的标记过程,本质是确定哪些对象还“活着”——即从一组根对象(GC Roots)出发,沿着引用链递归遍历所有可达对象,并打上“存活”标记。这个过程不涉及内存移动或复制,只做逻辑判断与状态记录。
标记阶段的核心机制
初始时,所有对象默认处于“未访问”状态(常以白色表示)。GC Roots(如栈帧中的局部变量、静态字段、JNI引用等)所直接引用的对象被率先标记为“待扫描”(灰色),随后逐个处理这些灰色对象:将其引用的其他白色对象也涂灰,自身则转为“已扫描完成”(黑色)。当灰色集合为空,标记结束,所有仍为白色的对象即判定为垃圾。
- 标记本身只需一个比特位(0/1)或颜色状态,开销低、实现简洁
- 标记顺序不影响结果正确性,但深度优先或广度优先会影响缓存友好性
- 单线程标记会暂停用户程序(Stop-The-World),影响响应延迟
为什么需要并发标记
在高吞吐或低延迟要求的系统中,长时间停顿不可接受。并发标记让GC线程与用户线程同时运行,避免STW,但带来新挑战:用户线程可能在标记过程中修改引用关系,导致漏标或误标。
- 典型问题包括“浮动垃圾”(本该回收却逃过本轮标记)和“漏标”(本该存活却被错判为垃圾)
- 解决漏标的关键是写屏障(Write Barrier):当用户线程修改引用时,强制将被修改的对象或其引用目标“重新入队”或“重标记”,确保不丢失可达路径
- 三色标记法是并发标记的常用抽象模型,它用白/灰/黑三种颜色刻画对象状态,并通过约束颜色流转规则保障安全性
实际工程中的折中设计
纯并发标记难以完全避免精度损失,因此主流JVM(如G1、ZGC)通常采用“初始标记→并发标记→最终标记”三阶段组合:
- 初始标记极短,仅标记GC Roots直接关联对象(需STW)
- 并发标记阶段与用户线程并行,利用写屏障维护一致性
- 最终标记(Remark)再次STW,处理写屏障缓冲区中残留的变更,确保标记完整性
这种分段策略在延迟控制与回收准确性之间取得平衡,既降低停顿时间,又避免因并发导致的严重回收错误。










