JVM学习日记⭐️HotSpot算法细节实现(下)⭐️

486 阅读4分钟

“这是我参与8月更文挑战的第19天,活动详情查看:8月更文挑战

🔉引言

前面提到,当前主流的垃圾回收器的判决对象存活的方法都是基于可达性分析法的,忘记的小伙伴可以点击【传送门】飞过去看看,那为了保证可达性分析的准确性,我们必须让世界静止,原因已经说明,忘记的小伙伴可以乘坐【时光机】看看,但是世界冻结的时间不能太长,虽然我们采用了各种优化技巧,使它的暂停变得非常短暂且固定了,可从GCRoots再往下就不是受我们所控制的了,那受谁的控制呢?java堆,如果java堆的容量大,那必然对象多,故标记更多对象产生的时间就更长。

📛并发的可达性分析

这是没有办法避免的事情,但是我们不能放任不管,道常无为,并不是不作为,而是不妄为,如果我们什么都不做,那标记阶段耗费的时间就会随着堆的增大几何倍的增加,标记阶段是所有追踪式垃圾回收算法的共同特征,势必会波及到几乎所有的垃圾收集器,所以,我们必须采取措施。

🍛三色标记

那我们能做什么呢?我们得对症下药💊,要解决或者降低用户线程的停顿,就必须要搞明白为什么在必须能保证一致性的快照下才能进行对象图的遍历?我们可以借助三色标记工具帮助我们推导:

  • 白色⬜️:表示对象尚未被垃圾收集器访问过
  • 黑色⬛️:表示对象被垃圾收集器访问过,且对象的所有引用都被扫描过
  • 灰色🔘:表示对象已经被垃圾收集器访问过

🔖对象消失

初始阶段,大家都一样,你白我也白,但是要是分析结束了,你还没被标记,那你就是不可达的白色对象了,如果看到的是黑色对象,那就说明已经被标记过了,可以存活,如果有其他对象引用指向黑色对象,无需重新扫描了,需要注意的是灰色是过度阶段,黑色对象不可能不经过灰色对象直接指向某个白色对象。

接下来,我们思考一下:如果收集器和用户线程并发工作会发生什么有意思的事情?收集器一边标记,用时用户线程在修改引用关系,那可能发生标记为存活的对象,被用户线程修改为消亡,这其实还能接受,等着下次再标记呗,最要命的是啥呢?我标记为死亡的,用户线程说:不行,还得用,还得活,得,程序错乱了,虚拟机懵了😨,到底听谁的?图如下:PS:看不到的话,证明还没画!

这就是“对象消失”问题,由Wilson1994年进行了理论证明,我们直接把结论搬过来就好,要记住,战争巨人的肩膀上看问题:

  • 赋值器插入了一条或多条从黑色对象到白色对象的新引用
  • 赋值器删除了全部从灰色对象到该白色对象的直接或间接的引用

🎰解决方案

那简单了要解决这个问题,我们只需要破坏条件即可,那我们就有了两种可行的方案,别问我是怎么知道的,记住与结论对着干就行,分别是增量更新Incremental Update)和原始快照(SnapShot At THe Beginning SATB)。

黑色对象一旦新插入指向白色对象引用时,它就不再是黑色对象了,要把这个新插入的引用记录下来,等并发结束后,再以该黑色对象为根对象,重新进行扫描,换言之就是变成灰色对象了,这是第一点。

那接下来说第二点,与第一点相同,当灰色对象要删除指向白色对象的引用关系时,也先记录下来,事后再以灰色对象为根,重新进行扫描,也就是说如果两个人跟你说的是不同的指令,为了避免发生矛盾,先记录下来,做好备份,再根据合适的场景选择去做,等事情过去,再问个明白。

📝题外话

我每天都会无数次意识到,我的物质生活精神生活很大程度上建立在他人的劳动成果之上,这些人有的尚健在,有的已故去。对于我已经得到和正在得到的一切,我必须竭尽全力做出相应的回报。

我渴望过简朴的生活,常常为自己过多地享用他人的劳动成果而深感不安。我不认为社会的阶级划分是合理的,归根结底是靠强制手段维系的。我还相信,简朴而平易的生活,对每个人的身心都是有益的,我是CocaCoder,一位新时代的码农。