HotSpot垃圾算法实现之并发的可达性分析
并发的可达性分析
根可达算法在理论上,需要冻结全部的用户线程运行。在根节点枚举步骤中,由于GC Roots相比整个Java堆中全部对象毕竟是极少数,且在OopMap优化下,带来的停顿时间非常短暂且相等固定。
问题一:堆越大,从GC Roots集合往下遍历对象图产生的STW越长,如何解决?
并发标记,让GC线程和用户线程同时执行。
问题二:如何并发标记对象图(有向图)中的垃圾?
三色标记法:
- 白色:未扫描前对象都是白色,等到扫描完成后,不可达的对象也是白色。
- 黑色:扫描完成且是可达的对象是黑色的,表示对象存活。
- 灰色:已经被GC线程访问过,但是至少有一个引用未扫描的对象未灰色,是黑白对象的分界线。
问题三:并发标记时,用户线程修改了引用产生对象消失的问题如何解决?
产生对象消失问题的2个必要条件:
- 赋值器插入了一条或多条从黑色对象指向白色对象的引用;
- 赋值器删除了从灰色对象到白色对象的直接或间接引用;
解决之道:破坏上面2个条件的其中一个即可。
增量更新 想要破坏的是第一个条件,当插入了黑色对象到白色对象的引用时,就将这个新插入的引用记录下来,等并发扫描完成后,再将这些记录的引用以黑色对象为根,重新扫描一次。说白了就是,黑色对象插入了指向白色对象的引用后就变成了灰色对象。
原始快照 想要破坏的是第二个条件,当灰色对象要删除指向白色对象的引用关系时,就将这个要删除的引用记录下来,等并发扫描完成后,再将这些记录的引用以灰色对象为根,重新扫描一次。说白了就是,无论引用关系删除与否,都会按照刚开始扫描的对象图快照来扫描。
总结: 无论是引用的插入还是删除,虚拟机都是通过写屏障来实现记录的。 CMS收集器采用增量更新方案实现并发标记,而 G1、Shenandoah则是用原始快照来实现。
参考资料
- 周志明 * 《深入理解Java虚拟机》