CMS 三色标记法

为什么引入三色标记法

为了提供 JVM 垃圾回收的性能,从 CMS 垃圾收集器开始,引入了并发标记的概念(此处的并发标记是指与用户线程一起工作)。引入并发标记的过程就会带来一个问题,在业务执行的过程中,会对现有的引用关系链出现改变。具体如下图:

在这里插入图片描述

当 GC 线程开始标记对象的时候,如果这个时候用户线程修改了 F 和 A 的引用,因为此时 A对象已经被遍历完成了,GC线程就不会再对 A 有新的标记操作,这样 GC 线程就会认为 B,C,D 对象没有被任何对象引用,就会被当成垃圾回收。

很明显在并发的情况下,“两色“的标记法是无法满足要求的。

三色标记的过程

为了解决并发的问题,我们可以引入中间的状态(灰色),当一个对象被标记的时候,会有下面几个过程:

  1. 首先被标记成灰色
  2. 检测当前所有的灰色对象,遍历子节点
  3. 如果子节点被遍历完了,把当前节点标记成黑色

在这里插入图片描述

在上图中,第一个过程是把 A,E 标记成灰色,后续再遍历 A,E 的子节点,发现了 A 有 C 节点,E 有 F 节点,这样 C,F在后续就会被标记成活着的对象(此处还会存在缺陷,后面讨论)

三色标记的问题

从上面的分析可以得出,三色标记法解决了并发的场景的引用链变动的问题,但是也会存在问题。

在上面的场景中,如果 GC 线程标记 A 成黑色后,用户线程修改了 A 的引用,这个时候 A 是黑色,C 因为没有找到引用的变量,还是会被当成垃圾回收。

CMS 如何解决

理解了问题的本质,问题就容易解决了,G1 收集器采用的 SATB 解决方案(略),CMS 采用了 Incremental Update 解决方案:如果发现对象子节点有新的引用,增加一个写入屏障,同时把黑色改成灰色

CMS 为什么还需要重新标记?

在采用了 Incremental Update 解决方案后,还是会存在一个巨大的缺陷,在上述的场景中,如果有多个 GC 线程对 A 标记,两个线程判断可能存在不一致,具体如下图:

在这里插入图片描述

在上面的场景中,我们假设GC 线程 1 发生在用户线程之前,GC 线程 2 发生在业务线程后:

当 GC 线程 1 发现 A 有没有,会把 A 变成黑色。

当 GC 线程 2 发现 A 有子节点,会把 A 变成灰色。

这样就对垃圾回收的结果产生了误判,所以CMS 在并发标记后还需要一次重新标记,当然这次重新标记会带来更长的 STW。
这个也许是 CMS 不是任何版本 JDK 的默认垃圾回收器了。

### 三色标记法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}") ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值