本文已收录至Github,推荐阅读 ? Java随想录

微信公众号:Java随想录

CSDN: 码农BookSea

你愈是少说你的伟大,我将愈想到你的伟大。——培根

目录
  • 三色标记算法
  • 增量更新
  • 原始快照

面试官:我们先从JVM基础开始问,了解三色标记算法吗?

我:额......不了解。

面试官:出去的时候记得把门带上。

现在Java面试真的已经是越来越卷了,很喜欢问底层实现原理。本篇来聊聊三色标记算法,也是Java面试的常客。

三色标记算法可以扯出增量更新和原始快照,聊好了会让面试官觉得你这小伙子有点东西。

一文弄懂三色标记算法

三色标记算法

既然叫三色标记算法,首先我们要搞明白是哪三色,三色是:黑色,白色,灰色

把遍历对象图过程中遇到的对象,按照是否访问过这个条件标记成以下三种颜色:

原书中的图画的很好,一目了然。

一文弄懂三色标记算法

一文弄懂三色标记算法

由于一些垃圾回收器存在垃圾回收线程和用户线程并发的情况(例如CMS的并发阶段),那么三色标记会有2个问题

Wilson于1994年在理论上证明了,当且仅当以下两个条件同时满足时,会产生“对象消失”的问题,即原本应该是黑色的对象被误标为白色:

因此,我们要解决并发扫描时的对象消失问题,只需破坏这两个条件的任意一个即可。由此分别产生了两种解决方案:增量更新(Incremental Update)原始快照(Snapshot At The Beginning,SATB)

这2种解决方案各破坏一个条件

增量更新

增量更新要破坏的是第一个条件,当黑色对象插入新的指向白色对象的引用关系时,就将这个新插入的引用记录下来,等并发扫描结束之后,再将这些记录过的引用关系中的黑色对象为根,重新扫描一次。这可以简化理解为,黑色对象一旦新插入了指向白色对象的引用之后,它就变回灰色对象了。

这其实有点像之前讲过类似OopMap的思想,本质也是维护了个映射关系,重新扫描的时候扫描这个映射关系就行了,不用全表扫描。

原始快照

原始快照要破坏的是第二个条件,当灰色对象要删除指向白色对象的引用关系时,就将这个要删除的引用记录下来,在并发扫描结束之后,再将这些记录过的引用关系中的灰色对象为根,重新扫描一次。这也可以简化理解为,无论引用关系删除与否,都会按照刚刚开始扫描那一刻的对象图快照来进行搜索。

以上无论是对引用关系记录的插入还是删除,虚拟机的记录操作都是通过写屏障实现的。写屏障,我们之前讲记忆集与卡表的时候介绍过的,可以理解为Spring中的AOP,目前为止卡表状态的维护,增量更新,原始快照都是基于写屏障

另外,CMS使用的是增量更新,G1使用的是原始快照

本篇文章就到这里,如果再遇见面试官问你类似的问题,你可以好好跟他扯皮咯。

如果本篇博客有任何错误和建议,欢迎给我留言指正。文章持续更新,可以关注公众号第一时间阅读。

一文弄懂三色标记算法

发表回复