三色标记法 

 根据可达性分析,从GC Roots开始进行遍历访问,按“是否访问过”这个条件标记成以下三种颜色:

黑色:本对象已访问过,而且本对象 引用到 的其他对象 也全部访问过了。 (自己标记完了,自己的孩子(包括多个孩子)也标记完了,都不是垃圾) 

灰色:本对象已访问过,但是本对象 引用到 的其他对象 尚未全部访问完。全部访问后,会转换为黑色。(自己标记完了,自己的孩子(包括多个孩子)没有标记)

白色:尚未访问过,对象即为GC Roots 不可达,可以进行回收。

1、CMS和G1都存在并发标记,并发标记解决了什么问题?

就是要减少标记停顿时间,让用户线程与垃圾回收线程同时运行,并发工作,也就是我们所说的并发标记阶段。

2、并发标记带来什么问题?

即标记期间应用线程还在继续跑,对象间的引用可能发生变化,多标漏标的情况就有可能发生。

①由于用户线程和垃圾回收线程同时进行,用户级线程可能产生浮动垃圾多标);

②同时会带来原本应该存活的对象标记为已消亡(漏标)这就回带来问题了,一个需要被引用的对象被回收了,那程序返回的结果一定是有问题的。

一、多标

此时垃圾线程已经把E标记为黑色或者灰色,而此时用户线程执行 

objD.fieldE = null ;

D、E发生断裂,因为E已经变为灰色或黑色了,其仍会被当作存活对象继续遍历下去。最终的结果是:这部分对象仍会被标记为存活,即本轮GC不会回收这部分内存。这部分本应该回收 但是 没有回收到的内存,被称之为“浮动垃圾”。浮动垃圾并不会影响垃圾回收的正确性,只是需要等到下一轮垃圾回收中才被清除。

二、 漏标

此时用户线程执行 

var G = objE.fieldG; 
objE.fieldG = null;  // 灰色E 断开引用 白色G 
objD.fieldG = G;  // 黑色D 引用 白色G

 此时E已经没有对G的引用了,所以不会将G放到灰色集合;尽管因为D重新引用了G,但因为D已经是黑色,不会再进行并发标记。最终导致的结果是:G会一直停留在白色集合中,最后被当作垃圾进行清除。这直接影响到了应用程序的正确性,是不可接受的

不难分析,漏标只有同时满足以下两个条件时才会发生:

  1. 条件一:灰色对象 断开了 白色对象的引用;即灰色对象 原来成员变量的引用 发生了变化。
  2. 条件二:黑色对象 重新引用了 该白色对象;即黑色对象 成员变量增加了 新的引用。

go语言的三色标记法_go语言的三色标记法

1、CMS是如何解决?

 增量更新(Incremental Update):就是当黑色对象插入新的指向白色对象的引用关系时, 就将这个新插入的引用记录下来,等并发扫描结束之后, 再将这些记录过的引用关系中的黑色对象为根, 重新扫描一次(重新标记阶段)。 这可以简化理解为, 黑色对象一旦新插入了指向白色对象的引用之后, 白色就变回灰色对象,这样就不会进行回收。

2、G1是如何解决?

SATB(snapshot at the beginning):

利用pre-write barrier,将所有即将被修改引用关系的白对象旧引用记录下来,最后以这些旧引用为根重新扫描一遍,以解决白对象引用被修改产生的漏标问题。

在引用修改时把原引用保存到satb_mark_queue中,每个线程都自带一个satb_mark_queue。在下一次的并发标记阶段,会依次处理satb_mark_queue中的对象,确保这部分对象在本轮GC中是存活的。