并发的可达性

前情提要,当前主流编程语言的垃圾收集器,基本上都是依靠 可达性分析算法 来判定对象是否存活。然而,可达性分析算法要求全过程都基于一个能保障一致性的快照中才能够进行分析,简单来说,就是必须全程冻结用户线程的运行,这样很影响运行效率。

为了减少用户线程冻结的影响,提高运行效率,在这里我们引入一个概念:并发标记。接下来,让我们一起去了解并发标记是什么。

并发标记的作用

首先提出一个问题,为什么全程冻结用户线程的运行,很影响运行效率?

根据 可达性分析算法 的核心概念,利用系列根对象(GC Roots )作为起始点,根据对象之间的引用关系搜索出一条引用链(Reference Chain),通过遍历引用链来判断对象的是否存活。

在这个过程中,根对象枚举的时间非常短暂且相对固定,然而,遍历所有引用链(对象图)所需要的时间与对象的数量成正比。因此,对象越多,对象之间的引用关系就越复杂,需要更多的时间去遍历所有的引用链来标记所有的对象。

并发标记的作用就是让垃圾回收线程和用户线程能够同时进行,并发执行。

并发标记的问题

那么,垃圾回收线程和用户线程并发执行的过程中会遇到什么问题?

为了更好的解释问题,需要引入三色标记(Tri-color Marking)进行辅助说明,在遍历所有的引用链(对象图)的过程中,按照 “是否访问过” 这个条件,将对象标记成以下三种颜色:

◉ 白色:
(1)表示对象尚未被垃圾收集器访问过。
(2)可达性分析开始前,所有对象都是白色的,如果分析结束后,依然是白色的对象,意味着它是不可达的,将会被回收。

◉ 黑色:
(1)表示对象已经被垃圾收集器访问过,而且对象的引用链已经遍历完成。(2)黑色的对象,意味着它是可达的,不会被回收。
(3)如果被其他对象引用,不需要重新遍历一遍。
(4)黑色的对象不可能直接(不经过灰色的对象)指向某个白色的对象。

◉ 灰色:
(1)表示对象已经被垃圾回收器访问过,但是对象的引用链没有遍历完成。
(2)灰色的对象在黑色的对象和白色的对象之间。
关于可达性分析的扫描过程, 把它看作对象图上一股以灰色为波峰的 波纹从黑向白推进的过程,如果用户线程此时是冻结的,只有收集器线程在工作,那不会有任何问 题。但如果用户线程与收集器是并发工作呢?收集器在对象图上标记颜色,同时用户线程在修改引用 关系——即修改对象图的结构,这样可能出现两种后果。一种是把原本消亡的对象错误标记为存活, 这不是好事,但其实是可以容忍的,只不过产生了一点逃过本次收集的浮动垃圾而已,下次收集清理 掉就好。另一种是把原本存活的对象错误标记为已消亡,这就是非常致命的后果了,程序肯定此 发生错误

1.初始状态,只有GC Roots是黑色的。

    图中的箭头是有像引用,对象要存活就必须要被黑色箭头指向才可以。只要是没有被黑色指向都会死亡。

并发的可达性_第1张图片 

2.扫描过程

这个过程灰色是黑白的分界线,是由黑过度到白色

并发的可达性_第2张图片

3.完成扫描

扫描完成后,黑色对象---存活,白色---死亡可回收对象

并发的可达性_第3张图片

4. 

图中黑色指向灰色过程中,前面切断原有的联系,左下角的白色球就是浮动垃圾。

并发的可达性_第4张图片

5.用户用线程在标记进行时候修改引用关系,扫描就不再顺利。比如在黑色指向灰色的过程中,正在扫描的灰色对象的一个引用被切断了,同时原来的应用对象与一扫描过的黑对象建立的引用关系。

并发的可达性_第5张图片

Wilson于1994年在理论上证明了,当且仅当以下两个条件同时满足时,会产生“对象消失”的问 题,即原本应该是黑色的对象被误标为白色: ·赋值器插入了一条或多条从黑色对象到白色对象的新引用; ·赋值器删除了全部从灰色对象到该白色对象的直接或间接引用。

因此,我们要解决并发扫描时的对象消失问题,只需破坏这两个条件的任意一个即可。由此分别 产生了两种解决方案:增量更新(Incremental Update)和原始快照(Snapshot At The Beginning, SATB)。

增量更新要破坏的是第一个条件,当黑色对象插入新的指向白色对象的引用关系时,就将这个新 插入的引用记录下来,等并发扫描结束之后,再将这些记录过的引用关系中的黑色对象为根,重新扫 描一次。这可以简化理解为,黑色对象一旦新插入了指向白色对象的引用之后,它就变回灰色对象 了。 原始快照要破坏的是第二个条件,当灰色对象要删除指向白色对象的引用关系时,就将这个要删 除的引用记录下来,在并发扫描结束之后,再将这些记录过的引用关系中的灰色对象为根,重新扫描 一次。这也可以简化理解为,无论引用关系删除与否,都会按照刚刚开始扫描那一刻的对象图快照来 进行搜索。 以上无论是对引用关系记录的插入还是删除,虚拟机的记录操作都是通过写屏障实现的。在 HotSpot虚拟机中,增量更新和原始快照这两种解决方案都有实际应用,譬如,CMS是基于增量更新 来做并发标记的,G1、Shenandoah则是用原始快照来实现 

你可能感兴趣的:(jvm,java,算法)