CMS三色标记

CMS(Concurrent Mark Sweep)中的三色标记(Tri-color Marking) 是垃圾回收过程中用于标记存活对象的算法,通过三种颜色(白色、灰色、黑色)标记对象的存活状态,解决了并发标记阶段应用线程与回收线程同时操作对象引用的问题。

一、三色标记的核心概念

三色标记将对象分为三种状态,通过颜色转换追踪对象的可达性:

  1. 白色:未被标记的对象(默认状态)。若标记结束后仍为白色,视为垃圾,将被清除。
  2. 灰色:已被标记,但其引用的子对象尚未完全标记(需继续遍历)。
  3. 黑色:已被标记,且其引用的所有子对象都已标记完成(无需再处理)。

核心流程:从 GC Roots(如栈引用、静态变量)开始,先标记为灰色,再遍历灰色对象的子对象(子对象标记为灰色),自身转为黑色,直到所有可达对象都被标记(灰色对象为空)。

二、并发标记中的问题与解决方案

三色标记的关键挑战是:并发标记时,应用线程可能修改对象引用,导致 “漏标”(存活对象被误判为垃圾)。需通过写屏障(Write Barrier) 解决。

可能的漏标场景:
  1. 场景 1:应用线程删除了黑色对象到白色对象的引用(导致白色对象失去可达性)。
  2. 场景 2:应用线程将白色对象的引用赋值给另一个白色对象(新引用链未被追踪)。
解决方案:通过 “增量更新” 或 “原始快照” 保证标记准确性

CMS 采用增量更新(Incremental Update) 策略:当黑色对象指向白色对象的引用被删除时,将黑色对象重新标记为灰色,确保其引用的子对象能被重新遍历。

三、三色标记示例(结合 CMS 并发流程)

假设内存中有以下对象引用关系:
GC Roots → A → B → CD → 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)。
  • 触发写屏障
    • 因 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 服务)。

这种机制平衡了垃圾回收的准确性和应用的可用性,是并发垃圾回收器的关键技术。

### 三色标记法在CMS垃圾回收器中的应用及原理 #### 1. 三色标记法的基本概念 三色标记法是一种用于并发标记存活对象的核心算法,通过颜色状态(白色、灰色、黑色)来跟踪对象的可达性。具体定义如下: - **白色**:表示尚未被垃圾收集器访问过,可能是垃圾的对象[^3]。 - **灰色**:表示已被垃圾收集器访问过,但其子引用尚未被扫描的对象。 - **黑色**:表示已被垃圾收集器访问过,且其所有子引用都已完全扫描的对象。 #### 2. CMS垃圾回收器中的三色标记CMS(Concurrent Mark-Sweep)垃圾回收器在老年代中使用三色标记法进行对象的存活检测。以下是三色标记法在CMS中的具体应用阶段: #### 3. 初始标记阶段 初始标记阶段由CMS线程单线程执行,会发生短暂的STW(Stop-The-World)。在此阶段,仅对根对象进行标记,并将其颜色从白色变为灰色[^1]。 #### 4. 并发标记阶段 在并发标记阶段,CMS线程与用户线程并发执行,不会发生STW。此阶段的主要任务是将灰色对象的所有可达对象标记为灰色,并最终将这些对象的颜色变为黑色。由于并发标记期间用户线程仍在运行,可能会导致漏标或多标问题,因此需要引入增量更新算法来解决这些问题。 #### 5. 重新标记阶段 重新标记阶段由CMS线程并发执行,会发生短暂的STW。此阶段的主要任务是对并发标记阶段中出现的漏标或错误标记的对象进行修正。通过增量更新算法,确保所有存活对象都被正确标记。 #### 6. 并发清理阶段 在并发清理阶段,CMS线程与用户线程并发执行,不会发生STW。此阶段的任务是清理所有仍然保持白色的对象,因为这些对象被认为是不可达的垃圾。需要注意的是,新产生的对象即使未被标记,也不会被误清理,这是因为CMS在清理过程中会跳过新分配的对象[^1]。 #### 7. 并发重置阶段 在并发重置阶段,CMS线程会重置本次GC过程中的标记数据,为下一次GC做好准备[^1]。 #### 8. 三色标记法的潜在问题及解决方案 三色标记法在并发标记期间可能会遇到以下问题: - **漏标问题**:当一个白色对象被灰色对象引用时,如果此时该白色对象被修改为指向另一个白色对象,则新的白色对象可能无法被标记为灰色。CMS通过增量更新算法解决了这一问题[^2]。 - **多标问题**:当一个黑色对象被修改为指向一个白色对象时,该白色对象可能无法被及时标记为灰色。CMS通过SATB(Snapshot-At-The-Beginning)算法解决了这一问题[^2]。 #### 9. 总结 三色标记法是CMS垃圾回收器的核心算法之一,通过将对象分为白色、灰色和黑色三种状态,有效地实现了对象的存活检测。尽管存在漏标和多标问题,但CMS通过增量更新和SATB算法成功地解决了这些问题,从而保证了垃圾回收的准确性。 ```python # 示例代码:模拟三色标记法的基本逻辑 class Object: def __init__(self, name): self.name = name self.color = "white" self.references = [] def mark_gray(obj): if obj.color == "white": obj.color = "gray" for ref in obj.references: mark_gray(ref) obj.color = "black" # 创建对象 obj1 = Object("obj1") obj2 = Object("obj2") obj3 = Object("obj3") # 建立引用关系 obj1.references.append(obj2) obj2.references.append(obj3) # 开始标记 mark_gray(obj1) # 输出结果 print(f"Object 1 Color: {obj1.color}") print(f"Object 2 Color: {obj2.color}") print(f"Object 3 Color: {obj3.color}") ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值