CMS(Concurrent Mark Sweep)中的三色标记(Tri-color Marking) 是垃圾回收过程中用于标记存活对象的算法,通过三种颜色(白色、灰色、黑色)标记对象的存活状态,解决了并发标记阶段应用线程与回收线程同时操作对象引用的问题。
一、三色标记的核心概念
三色标记将对象分为三种状态,通过颜色转换追踪对象的可达性:
- 白色:未被标记的对象(默认状态)。若标记结束后仍为白色,视为垃圾,将被清除。
- 灰色:已被标记,但其引用的子对象尚未完全标记(需继续遍历)。
- 黑色:已被标记,且其引用的所有子对象都已标记完成(无需再处理)。
核心流程:从 GC Roots(如栈引用、静态变量)开始,先标记为灰色,再遍历灰色对象的子对象(子对象标记为灰色),自身转为黑色,直到所有可达对象都被标记(灰色对象为空)。
二、并发标记中的问题与解决方案
三色标记的关键挑战是:并发标记时,应用线程可能修改对象引用,导致 “漏标”(存活对象被误判为垃圾)。需通过写屏障(Write Barrier) 解决。
可能的漏标场景:
- 场景 1:应用线程删除了黑色对象到白色对象的引用(导致白色对象失去可达性)。
- 场景 2:应用线程将白色对象的引用赋值给另一个白色对象(新引用链未被追踪)。
解决方案:通过 “增量更新” 或 “原始快照” 保证标记准确性
CMS 采用增量更新(Incremental Update) 策略:当黑色对象指向白色对象的引用被删除时,将黑色对象重新标记为灰色,确保其引用的子对象能被重新遍历。
三、三色标记示例(结合 CMS 并发流程)
假设内存中有以下对象引用关系:
GC Roots → A → B → C,D → E(D 是未被 GC Roots 引用的孤立对象)。
1. 初始标记(STW)
- 只标记 GC Roots 直接关联的对象(A),标记为灰色。
- 其他对象(B、C、D、E)为白色。
- 状态:A(灰),B(白),C(白),D(白),E(白)。
2. 并发标记(与应用线程并行)
- 回收线程开始遍历:
- A 的子对象 B 被标记为灰色,A 转为黑色。
- B 的子对象 C 被标记为灰色,B 转为黑色。
- C 无子对象,转为黑色。
- 此时应用线程执行操作:
- 删除 B 到 C 的引用(
B.field = null)。 - 新增 A 到 E 的引用(
A.field = E)。
- 删除 B 到 C 的引用(
- 触发写屏障:
- 因 A(黑色)新增了对 E(白色)的引用,A 被重新标记为灰色(增量更新策略)。
- 状态:A(灰),B(黑),C(黑),D(白),E(白)。
3. 重新标记(STW)
- 处理写屏障记录的灰色对象(A):
- A 的新子对象 E 被标记为灰色,A 转为黑色。
- E 无子对象,转为黑色。
- 最终存活对象:A(黑)、B(黑)、C(黑)、E(黑)(C 虽被 B 删除引用,但因已标记为黑色,仍视为存活)。
- 垃圾对象:D(白)。
4. 并发清除
- 清除白色对象 D,存活对象(A、B、C、E)保留。
原因讲解见三色标记中例子说明-CSDN博客
四、总结
- 三色标记是 CMS 并发标记的核心算法,通过白、灰、黑三色追踪对象存活状态,实现高效的并发标记。
- 漏标问题通过 “写屏障 + 增量更新” 解决:当黑色对象引用白色对象时,强制将黑色对象变回灰色,确保子对象被重新标记。
- 三色标记的优势:允许应用线程与回收线程并发执行,大幅减少 STW 时间,适合低延迟场景(如 Web 服务)。
这种机制平衡了垃圾回收的准确性和应用的可用性,是并发垃圾回收器的关键技术。
815

被折叠的 条评论
为什么被折叠?



