5.1 三色标记(针对并发标记,没有stw)
三色标记最大的好处是可以异步执行,从而可以以中断时间极少的代价或者完全没有中断来进行整个 GC。
三色标记法很简单。首先将对象用三种颜色表示,分别是白色、灰色和黑色。
黑色:根对象,或者该对象与它的子对象都被扫描过。
灰色:对本身被扫描,但是还没扫描完该对象的子对象。
白色:未被扫描对象,如果扫描完所有对象之后,最终为白色的为不可达对象,既垃圾对象
5.2 GC并发情况下的漏标问题
A.c=C
B.c=null
CMS 中的解决方案
Incremental Update 算法
当一个白色对象被一个黑色对象引用,将黑色对象重新标记为灰色,让垃圾回收器重新扫描
G1 中的解决方案
SATB(snapshot-at-the-beginning)
刚开始做一个快照,当 B 和 C 消失的时候要把这个引用推到 GC 的堆栈,保证 C 还能被 GC 扫描到,最重要的是要把这个引用推到 GC 的堆栈,是灰色对象指向白色的引用,如果一旦某一个引用消失掉了,我会把它放到栈(GC 方法运行时数据也是来自栈中),我其实还是能找到它的,我下回直接扫描他就行了,那样白色就不会漏标。对应G1的垃圾回收过程中的:
最终标记( Final Marking)
对用户线程做另一个短暂的暂停,用于处理并发阶段结后仍遗留下来的最后那少量的 SATB 记录(漏标对象)。
5.3 跨代引用
堆空间通常被划分为新生代和老年代。由于新生代的垃圾收集通常很频繁,如果老年代对象引用了新生代的对象,那么回收新生代的话,需要跟踪从老 年代到新生代的所有引用,所以要避免每次 YGC 时扫描整个老年代,减少开销。
RSet(记忆集)
记录了其他 Region 中的对象到本 Region 的引用, RSet 的价值在于使得垃圾收集器不需要扫描整个堆,找到谁引用了当前分区中的对象,只需要扫描 RSet 即可。 RSet 本身就是一个 Hash 表,如果是在 G1 的话,则是在一个Region 区里面
5.4 安全点与安全区域
安全点
用户线程暂停,GC 线程要开始工作,但是要确保用户线程暂停的这行字节码指令是不会导致引用关系的变化。所以 JVM 会在字节码指令中,选一些指令, 作为“安全点”,比如方法调用、循环跳转、异常跳转等,一般是这些指令才会产生安全点。为什么它叫安全点,是这样的,GC 时要暂停业务线程,并不是抢占式中断(立马把业务线程中断)而是主动是中断。 主动式中断是设置一个标志,这个标志是中断标志,各业务线程在运行过程中会不停的主动去轮询这个标志,一旦发现中断标志为 True,就会在自己最近 的“安全点”上主动中断挂起。
安全区域
为什么需要安全区域?
要是业务线程都不执行(业务线程处于 Sleep 或者是 Blocked 状态),那么程序就没办法进入安全点,对于这种情况,就必须引入安全区域。安全区域是指能够确保在某一段代码片段之中, 引用关系不会发生变化,因此,在这个区域中任意地方开始垃圾收集都是安全的。我们也可以把安全区域看作被扩展拉伸了的安全点。
