引言:在JVM中,使用可达性分析算法来判断一个对象是否存活。在Serial和Parallel收集器中,可达性分析的过程是STW的,这意味着在标记的过程中,对象的引用关系没有发生改变,从GC Root开始扫描,可以得到全部存活的对象。但是在CMS,G1等垃圾收集器中,采用了并发标记的方式来遍历对象图,毫无疑问,这缩短了STW的时间,但是也带来了新的问题,而增量更新和原始快照就是用来解决这个问题的不同方式。
一 并发标记的问题
采用了并发标记,可以让用户线程和GC线程同时工作,但是也带来了新的问题。
1 浮动垃圾
在进行并发标记的时候,无法处理初始标记以后产生的对象,这些对象称为浮动垃圾,这些浮动垃圾如果过多,会导致堆没有空间可以存放这些对象,因为这时候还在进行GC,旧的对象没有被回收。但这相对来说还是可控的,可以适当调整触发GC的堆大小的阈值来尽量避免这种情况的发生。
2 对象消失
在并发标记的时候,用户能够操作对象,这就有可能使得引用关系发生修改,使得所有指向本来活的对象的引用全部消失,那按照可达性分析算法,此时对象会被判定为死亡,但是实际这个对象是存活的。由于这个问题相对来说比较严重,所以我们下文以说明如何解决对象消失问题为主。
上面是用户线程修改引用关系前后的对比图。虚线代表引用已经被删除。
当同时满足以下两个条件时,就会出现对象消失的情况。
1 从黑色对象到白色对象增加了新的引用关系。
2 灰色对象直接或间接删除了到这个白色对象的全部引用关系。
因为黑色对象是不能再被访问的,而灰色对象又删除了到这个白色对象的全部引用关系,所以就造成了该白色对象本来是存活的,但是因为在扫描路径中没有出现而被当成死亡对象。
二 如何解决对象消失
为了解决对象消失的问题,在JVM中有两种方式,分别是增量更新和原始快照。在CMS垃圾收集器中使用增量更新,在G1垃圾收集器中使用原始快照。