三色标记算法 SATB

用处

G1在并行标记垃圾的时候会使用这个算法
主要是参考这个视频的听译

算法描述

将所有对象分为三种颜色

  • 白色:没有检查
  • 灰色:自身被检查了,成员没被检查完(可以认为访问到了,但是正在被检查,就是图的遍历里那些在队列中的节点)
  • 黑色:自身和成员都被检查完了

在这里插入图片描述
这是一个中间状态
根节点都是黑的(自己检查了,成员也都检查完了)
中间有些灰的
还有一些没被检查到的白的

把灰色的对象都放到队列中
然后从队列中取出一个灰色对象,假设是下图中的红色圈住的这个灰色对象
在这里插入图片描述
然后我们检查他的所有成员对象,并把那些变成灰色,放到队列中,自己变成黑色(检查完了)
在这里插入图片描述
再举个例子,再从队列中取出来的是上面那连续两个灰色的对象,然后检查他的孩子,孩子变灰,放入队列,自身变黑
在这里插入图片描述
这些叶子节点,指向null,或者指向基本类型(int, long),所以他们也黑了
在这里插入图片描述
所以就发现剩下那些白的,那就是垃圾了(无法到达)

注意,从来不会有黑色对象指向白色对象,NEVER!

  • 黑色对象会指向灰色对象,代表正在处理灰色对象
  • 灰色对象会指向白色对象,代表还没检查白色对象
  • 但是绝不会有黑色对象指向白色对象
  • 黑色对象代表自己的孩子都检查过了,所以黑色对象的孩子不可能是白的(白色没被检查过)

However!
别忘了在我们标记的时候,Application还在运行着呢,他可能会修改这个图的结构,引入一个问题:Lost Object Problem (漏标)
在这里插入图片描述
想象以下情况
我们正在遍历图
队列中有B这个灰色对象
然后我们的标记线程stop了
Application线程开搞 写入 A.c = C
在这里插入图片描述
Application线程 写入 B.c = null
在这里插入图片描述
OK,这确实是Application可以干的事情😂
然后我们回到了垃圾收集线程,从队列中拿出B这个灰色对象,发现B没有孩子了,ok标成黑色的吧
在这里插入图片描述
这就有问题了
因为C现在是白的,我们会认为他是垃圾,然后回收
但是实际上他还有A引用呢
那么我们回收C然后修改这块内存,就可能导致JVM crash了

怎么解决呢?
可以看到,发生这种bug的情况需要以下两个条件同时发生
1.灰色不再指向白色
2.黑色指向这个白色

所以,要解决这个问题,要么就从这两个条件入手

CMS是从条件2入手搞的;G1是从条件1入手搞的

为了防止上面说的那种情况,G1就说,那行吧,我们就继续认为C是活着的吧,别把他给回收了(当然也可能C真的是垃圾而没被回收,产生了floating garbage,不过也没关系,因为下次回收,如果C真的没人引用了,我们还是能把C给回收了)

具体怎么搞?
又用到我们的write barrier(JVM插入一小段代码到我们的应用程序中)
每次有指向空(B.c = null)都会运行这一小段代码(记录下这种边角情况,放到队列中,后面remark阶段处理)

SnapshotAtTheBeginning(SATB)

  • 在初始标记阶段保存对象图
  • 遇到C这种情况,把他放到队列中,在remark阶段处理
  • 可能会产生floating garbage,在下一个周期回收
  • 5
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值