GC Roots只占堆的很小部分,并且在各种优化技巧(如OopMap)的加持下,带来的停顿已经是非常短暂且固定的了。
可从GC Roots再继续往下遍历对象图,这一步骤的停顿就要与Java堆的容量直接成正比了。
为了降低线程停顿时间,就需要并发的进行可达性分析。如下就是并发可达性分析的细节。
1、三色标记
白色: 未被扫描过
黑色: 自己以及子引用均被扫描过
灰色: 扫描过,但至少还存在一个引用没有被扫描过。
2、动态扫描会有什么问题
GC Roots扫描过程中,用户线程动态的改变了对象的引用,造成如下两种情况
1、标记为存活的对象,不需要了,变成可清除得了。 ---这种情况可以容忍,产生了浮动垃圾,下次就可以清除。
2、标记为清除的对象,变成了需要存活。 ---这种情况程序一定发生错误。
如下图:
image.png
3、分析情况
当以下两个条件同时满足的时候,才会发生黑色对象误标记为白色对象。
1、赋值器插入了一条或多条从黑色对象到白色对象的新引用。
2、赋值器删除了全部从灰色对象到该白色对象的直接或间接引用。
4、如何解决
只要破坏了上述其中一条即可
1、增量更新
破坏第一个条件
当黑色对象插入新的指向白色对象的引用关系时,就将这个新插入的引用记录下来,等并发扫描结束之后,再将这些记录过的引用关系中的黑色对象为根,重新扫描一次。这可以简化理解为,黑色对象一旦新插入了指向白色对象的引用之后,它就变回灰色对象了。
例如CMS。
2、原始快照
破坏第二个条件
当灰色对象要删除指向白色对象的引用关系时,就将这个要删除的引用记录下来,在并发扫描结束之后,再将这些记录过的引用关系中的灰色对象为跟,重新扫描一次。这也可以简化理解为,无论引用关系删除与否,都会按照刚刚开始扫描那一刻的对象图快照来进行搜索。
例如G1、Shenandoah。
以上无论是对引用关系记录的插入还是删除,虚拟机的记录操作都是通过写屏障
实现的。
CMS使用的是增量更新。
网友评论