对象消息的情况二
下面再给各位看看另外一种"对象消失"的现象:
上面演示的是用户线程切断引用后重新被黑色对象引用的对象就是原来引用链的一部分。
对象7和对象10本来就是原引用链(根节点->5->6->7->8->11->10)的一部分。修改后的引用链变成了(根节点->5->6->7->10)。
当扫描完成后,对象图就变成了这个样子:
由于黑色对象不会重新扫描,这将导致扫描结束后对象10和对象11都会回收了。他们都是被修改之前的原来的引用链的一部分。
所以,回到最开始的疑问:并发标记带来了什么问题?
经过我们上面三种情况(一种正常情况,两种"对象丢失"的情况)的动图分析,和扫描完成后的最终对象图进行分析对比,我们知道了,并发标记除了会产生浮动垃圾,还会出现"对象消失"的问题。
怎么解决"对象消失"问题呢?
有一个大佬叫Wilson,他在1994年在理论上证明了,当且仅当以下两个条件同时满足时,会产生"对象消失"的问题,原来应该是黑色的对象被误标为了白色:
条件一:赋值器插入了一条或者多条从黑色对象到白色对象的新引用。
条件二:赋值器删除了全部从灰色对象到该白色对象的直接或间接引用。
你在结合我们上面出现过的图捋一捋上面的这两个条件,是不是当且仅当的关系:
黑色对象5到白色对象9之间的引用是新建的,对应条件一。
黑色对象6到白色对象9之间的引用被删除了,对应条件二。
由于两个条件之间是当且仅当的关系。所以,我们要解决并发标记时对象消失的问题,只需要破坏两个条件中的任意一个就行。
于是产生了两种解决方案:增量更新(Incremental Update)和原始快照(Snapshot At The Beginning,SATB)。
在HotSpot虚拟机中,CMS是基于增量更新来做并发标记的,G1则采用的是原始快照的方式。
什么是增量更新呢?
增量更新要破坏的是第一个条件(赋值器插入了一条或者多条从黑色对象到白色对象的新引用),当黑色对象插入新的指向白色对象的引用关系时,就将这个新插入的引用记录下来,等并发扫描结束之后,再将这些记录过的引用关系中的黑色对象为根,重新扫描一次。
可以简化的理解为:黑色对象一旦插入了指向白色对象的引用之后,它就变回了灰色对象。
下面的图就是一次并发扫描结束之后,记录了黑色对象5新指向了白色对象9:
这样对象9又被扫描成为了黑色。也就不会被回收,所以不会出现对象消失的情况。
什么是原始快照呢?
原始快照要破坏的是第二个条件(赋值器删除了全部从灰色对象到该白色对象的直接或间接引用),当灰色对象要删除指向白色对象的引用关系时,就将这个要删除的引用记录下来,在并发扫描结束之后,再将这些记录过的引用关系中的灰色对象为根,重新扫描一次。
这个可以简化理解为:无论引用关系删除与否,都会按照刚刚开始扫描那一刻的对象图快照开进行搜索。
需要注意的是,上面的介绍中无论是对引用关系记录的插入还是删除,虚拟机的记录操作都是通过写屏障实现的。写屏障也是一个重要的知识点,但是不是本文重点,就不进行详细介绍了。
只是补充两点:
1.这里的写屏障和我们常说的为了解决并发乱序执行问题的"内存屏障"不是一码事,需要区分开来。
2.写屏障可以看作虚拟机层面对"引用类型字段赋值"这个动作的AOP切面,在引用对象赋值时会产生一个环形通知,供程序执行额外的动作,也就是说赋值的前后都在写屏障的覆盖范畴内。在赋值前的部分的写屏障叫做写前屏障(Pre-Write Barrier),在赋值后的则叫作写后屏障(Post-Write Barrier)。
所以,经过简单的推导我们可以知道:
增量更新用的是写后屏障(Post-Write Barrier),记录了所有新增的引用关系。
原始快照用的是写前屏障(Pre-Write Barrier),将所有即将被删除的引用关系的旧引用记录下来。
最后说一句(求关注)
1.本文大部分内容来源于《深入理解Java虚拟机(第三版)》,只是我觉得三色标记这个点,仅仅用图片和文字是很难描述清楚的,所以我加上自己的理解做了动图。强烈建议先去阅读第三版相关内容,如果没有读明白,再来读这篇文章,应该能更好的理解。
2.最近有很多读者在找我修改简历、咨询工作的相关事情了,我就知道马上又要开始春招了。
其实我也不是很有资格给你们修改简历,也不是一个技术很牛逼的人,只是把我知道的分享出来了而已,不仅能让我巩固知识,还是倒逼我进行知识输入,在此之外还能对你有一点点帮助,那就是我文章的全部价值所在。
另外如果你正在经历春招或者社招,有兴趣的可以阅读一下我之前的这篇文章,看看是否有一点点帮助:
《面试了15位来自985/211高校的2020届研究生之后的思考》
才疏学浅,难免会有纰漏,如果你发现了错误的地方,还请你留言给我指出来,我对其加以修改。
如果你觉得文章还不错,你的转发、分享、赞赏、点赞、留言就是对我最大的鼓励。
感谢您的阅读,我坚持原创,十分欢迎并感谢您的关注。
以上。
欢迎关注公众号【why技术】,坚持输出原创。分享技术、品味生活,愿你我共同进步。