分代回收
分代回收这个并不是一个实际的算法。这是一个思想。由于在堆中,又被分为年轻代和老年代。年轻代又被分为eden区,survivor0区survivor1区。又称为from区和to区。 分代回收,就是根据在不同的区中,使用不同的垃圾回收算法。 使用最恰当的算法。
年轻代:在年轻代使用的就是标记复制算法。
老年代:使用的就是标记整理算法
为什么这么设计呢? 在年轻代的对象都是朝生夕死。所以对象要频繁的进行gc,这时标记复制算法效率是最高的。而在老年代的对象就是老不死的。不容易死,gc的频率也会很低,所以不用保证效率,保证内存使用率上。所以标记整理就很适合。
总结,年轻代注重时间,老年代注重空间。
三色标记
上篇说的标记清除等算法。中的标记。不仅仅只是简单的标记。这里用了三色标记。
黑色,灰色,白色。
当一个对象被标记,并且,这个对象内部属性所引用的对象也被标记时,这时就是黑色。当该对象被标记,但属性所引用的对象未被标记时,这时就是灰色。当对象未被标记时,这时就是白色。
并发漏标
并发漏标问题,就是当垃圾回收线程,进行三色标记时,此时用户线程并没有停,他们在并发的执行。所以当进行标记时,用户线程很有可能改变对象之间的引用关系。漏标问题就是,本该被标记的对象并没有被标记上。接下来有两种场景。

最开始。圈起来中的白色对象,最后应该会被标记为黑色。但此时当用户线程断开了,白色对象与灰色对象的引用关系。并把白色对象改为与已经被标记完的黑色对象上。由于已经被标记完了,不会再进行重新标记。所以此时,白色对象并不会被标记。但他又不是垃圾对象。所以会产生漏标问题。

第一种是修改已存在的对象之间的引用关系。这种就是添加新对象到已经被标记完的对象上,此时也不会被标记到。也会产生漏标问题。
解决方案
有两种解决方案:
- Incremental Update
- 第一种,只要赋值发生,就记录被赋值的对象。(当一个白色对象被一个黑色对象引用,将黑色对象重新标记为灰色,让垃圾回收器重新扫描。)
- Incremental Update关注的是引用关系的增加,当发现有可达的引用增加,便开始重新标记。
- snapshot-at-the-beginning 快照
- 第二种,新加对象会被记录,被删除引用的对象也会被记录。(SATB通过快照记录引用关系,一旦发现有引用删除,通过查看快照记录的引用关系,重新标记)
- 最终标记( Final Marking):对用户线程做另一个短暂的暂停,用于处理并发阶段结后仍遗留下来的最后那少量的 SATB 记录(漏标对象)。
Incremental Update算法和SATB算法对比:
Incremental Update算法注重的是被赋值的对象,SATB算法注重的是与其相反,是被删除引用的对象,是新增的对象。
效率上,SATB效率要比Incremental Update要高。Incremental Update算法当发现该对象又有可达对象时,又会重新进行遍历一遍,SATB就仅仅只会查看被删除引用对象或新增对象的引用关系。进行标记,效率大大提高
本文使用 文章同步助手 同步