三色标记-垃圾收集器底层算法

三色标记

前言

三色标记相信大家也有所耳闻,但是都没有过深入的了解。小编在之前和同事交流的过程中,了解到很多大厂在问虚拟机问题的时候会问到三色标记的问题。所以想再今天和大家分享一下自己对三色标记的理解。如果有理解的有问题的地方,欢迎大家指正。那么就让我们进入三色标记的学习中吧!


提示:以下是本篇文章正文内容,下面案例可供参考

一、三色标记是什么?

三色标记算法是把在Gc Root可达性分析算法遍历对象的过程中,遇到的对象进行“黑,灰,白”三种颜色的标记。
三色标记操作的阶段是在CMS的并发标记阶段,因为用户的线程也在执行,所以已经标记的对象的引用可能会发生变化。**多标和漏标**的情况都会发生,漏标主要是通过三色标记算法来解决的。

二、三色的介绍

1.黑色

黑色表示对象已经被垃圾收集器访问过,并且这个对象的所有引用都被扫描到了。黑色对象代表已经扫描过,是安全存活的,如果有其他对象的引用指向黑色的对象,不需要重新扫描。

2.灰色

灰色表对象已经被垃圾收集器访问过,但是这个对象的部分引用未被访问到。

3.白色

白色表示对象还没有被垃圾收集器访问过。显然处于可达性分析的初始阶段,如果可达性分析已经结束了,对象还是标记为白色则认为这个对象的垃圾对象。

在这里插入图片描述

上图关系的维护都在并发标记阶段维护,在重新标记阶段处理,这两种方式都是处理漏标的情况

  1. 在上图中对象A到对象D新增关联关系,在HotSpot虚拟机中会新增一个写屏障,用于记录新增关系,内部维护的是一个集合。当在重新标记的阶段,就会扫描整个集合。也就是三色标记中的增量更新
  2. 在上图中对象B到对象D删除了关联关系,在HotSpot虚拟机中会新增一个写屏障,用于记录对象间删除的关系。在重新标记阶段,扫描集合,将删除的对象直接标记为黑色(浮动垃圾),等待下次Gc再去回收。这个是三色标记中的原始快照

三、浮动垃圾

浮动垃圾的产生在下一次Gc过程中再去标记收集

  1. 在并发标记阶段,如果运行的方法结束,栈帧被销毁,栈帧中的局部变量作为Gc Root遍历的引用对象集在之前标记为非垃圾对象,但是实际上目前是垃圾对象。本轮的并发清除阶段不会被清除。这类被称为浮动垃圾
  2. 在并发标记和并发清除阶段,新生成的对象会被直接标记成黑色,等待下次Gc再被回收。这类也称为浮动垃圾
  3. 在并发标记阶段,如果对象之间的关系发生了删除,这时候虚拟机内部通过写屏障维护一个集合,这个集合在重新标记阶段会把所以删除关系的引用对象,设置成黑色。这类也是浮动垃圾

四、读写屏障

1.为什么HotSpot虚拟机需要提供一个读写屏障呢?带着疑问去学习我们能了解的更快。

读写屏障主要解决的问题是漏标的问题。漏标对象会导致对象被当成垃圾回收掉。这对于任何程序都是很严重的BUG。必须要解决。因此HotSpot虚拟机为我们提供了两种方案来解决这个问题:增量更新和原始快照

  1. 增量更新:增量更新就是在黑色对象插入新的白色对象的引用时,就把这个引用记录下来。等并发扫描后,重新以黑色对象为根开始扫描整个引用链。也可以理解为当黑色对象插入新的白色引用时,会变成灰色。
  2. 原始快照:原始快照就是在灰色对象要删除白色对象的引用时,就把这个引用记录下来。等扫描结束后,将记录中的引用关系为灰色的为根进行再次扫描,将扫描到的白色对象直接设置成黑色。(产生的浮动垃圾在下次Gc的时候再去收集)

2.以上引用关系的新增和删除,都是通Hotspot虚拟机的写屏障实现的


3.说了那么多,那么写屏障在HotSpot虚拟机中到底是如何实现的呢?

所谓的写屏障,其实就是在赋值阶段的前后,加入一些操作。(思路可以参考Spring中的AOP)

void oop_field_store(oop* field, oop new_value) {  
    pre_write_barrier(field);          // 写屏障-写前操作
    *field = new_value; 
    post_write_barrier(field, value);  // 写屏障-写后操作
}

写屏障实现STAB,在写前记录下原来的引用对象。

void pre_write_barrier(oop* field) {
    oop old_value = *field;    // 获取旧值
    remark_set.add(old_value); // 记录原来的引用对象
}

写屏障实现增量更新,在写后记录下对象间新增引用。

void post_write_barrier(oop* field, oop new_value) {  
    remark_set.add(new_value);  // 记录新引用的对象
}

四、总结

CMS垃圾收集器并发收集阶段漏标的解决方案:写屏障+增量更新
后面我还会介绍G1垃圾收集器的原理,和CMS垃圾收集器还是有很多相似的地方。这边小小的透露下G1垃圾收集器在并发扫描阶段出现了漏标会采用:写屏障+原始快照的方案。

那么为什么G1会选择这种方案呢?大家可以思考一下。顺带大家在思考一个阿里的面试题:为什么G1要选择使用原始快照,而cms选择使用增量更新呢?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

LeoZhuhui1995

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值