三色标记的漏标问题及两种解决方案

什么是三色标记

三色标记是在cms和g1中使用的垃圾追踪算法

  • 黑色

    从GCRoots开始,已扫描过它全部引用的对象,标记为黑色

  • 灰色

    扫描过对象本身,还没完全扫描过它全部引用的对象,标记为灰色

  • 白色

    还没扫描过的对象,标记为白色

所以,从GCRoots开始,顺着一直向下扫描,用可达性分析算法,最后所有的白色对象,都是垃圾对象,可以回收

三色标记的漏标问题

我们采用一个最简单的模型,只有三个对象

  1. 某个状态下,黑色->灰色->白色
    在这里插入图片描述

  2. 如果一切顺利,不发生任何引用变化,gc线程顺着灰色的引用向下扫描,最后都变成黑色,都是存活对象
    在这里插入图片描述

  3. 但是如果出现了这样一个状况,在扫描到灰色的时候,还没有扫描到这个白色对象,此时,黑色对象引用了这个白色对象,而灰色对象指向了别人,或者干脆指向了null,也就是取消了对白色对象的引用

在这里插入图片描述
4. 那么我们会发现一个问题,根据三色标记规则,gc
会认为,黑色对象是本身已经被扫描过,并且它所有指向的引用都已经被扫描过,所以不会再去扫描它有哪些引用指向了哪些对象

然后,灰色对象因为取消了对白色对象的引用,所以后面gc开始扫描所有灰色对象的引用时候,也不会再扫描到白色对象

最后结果就是,白色对象直到本次标记扫描结束,也是白色,根据三色标记规则,认为它是垃圾,被清理掉

但是实际情况,它明显是被引用的对象,是绝对不能当做垃圾来清除的,因为漏标,最后被当垃圾清理掉了

在这里插入图片描述

漏标的两个充要条件

  • 有至少一个黑色对象在自己被标记之后指向了这个白色对象
  • 所有的灰色对象在自己引用扫描完成之前删除了对白色对象的引用

这两个条件,必须全满足,才会造成漏标问题.

换言之,我们破坏任何一个条件.这个白色对象,就不会再被漏标

这样就产生了两个解决办法

CMS采用的是增量更新

​ 增量更新破坏的是第一个条件,我们在这个黑色对象增加了对白色对象的引用之后,将它的这个引用,记录下来,在最后标记的时候,再以这个黑色对象为根,对它的引用进行重新扫描.

​ 可以简单理解为,当一个黑色对象增加了对白色对象的引用,那么这个黑色对象就被变灰

​ 这样有一个缺点,就是会重新扫描这个黑色对象的所有引用,比较浪费时间

G1采用的是原始快照

​ 原始快照破坏的是第二个条件,我们在这个灰色对象取消对白色对象的引用之前,将这个引用记录下来,在最后标记的时候,再以这个引用指向的白色对象为根,对它的引用进行扫描

​ 可以简单理解为,当一个灰色对象取消了对白色对象的引用,那么这个白色对象被变灰

​ 这样做的缺点就是,这个白色对象有可能并没有黑色对象去引用它,但是它还是被变灰了,就会导致它和它的引用,本来应该被垃圾回收掉,但是此次GC存活了下来,就是所谓的浮动垃圾.其实这样是比较可以忍受的,只是让它多存活了一次GC而已,浪费一点点空间,但是会比增量更新更省时间.
在这里插入图片描述

  • 23
    点赞
  • 48
    收藏
    觉得还不错? 一键收藏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值