首页IT科技三色标软件(一文弄懂三色标记算法)

三色标软件(一文弄懂三色标记算法)

时间2025-08-01 19:53:51分类IT科技浏览6969
导读:本文已收录至Github,推荐阅读 ? Java随想录...

本文已收录至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使用的是原始快照                    。

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

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

声明:本站所有文章    ,如无特殊说明或标注                  ,均为本站原创发布    。任何个人或组织                          ,在未征得本站同意时        ,禁止复制                、盗用                          、采集          、发布本站内容到任何网站            、书籍等各类媒体平台                  。如若本站内容侵犯了原著者的合法权益             ,可联系我们进行处理                          。

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
读Java8函数式编程笔记06_Lambda表达式编写并发程序 quark网盘(Quarkus入门体验,22ms启动一个Web服务)