垃圾收集器多标和漏标的概念

前言

三色标记:在并发标记中程序还在跑,这个时候对象间的引用会发生变化,多标和漏标会发生。

这里我们引入三色标记的概念:把GC Roots可达性分析算法遍历对象的过程中,按照“是否访问过”这个条件标记以下三种情况

黑色:被垃圾收集器访问过,已经标记过是非垃圾对象。如果有其他对象引用指向了它,那么它也不会在扫描。比如下图的A和D一开始只有A 但是后面有个成员属性d有了引用 那么这个A已经是黑色对象就不会再扫描了(下方漏标详解)

黑色对象不可能直接(不经过灰色对象)指向某个白色对象

灰色:这个对象下的部分对象已经标记过,但是没有扫描完(至少还有一个对象的引用没有被扫描过)

白色:表示对象还没有被扫描过。显然在可达性分析的前期,所有对象都是白色,若是在分析结束阶段,仍然是白色,代表不可达被回收

多标和漏标

多标

在并发标记的时候标记了GCROOT这个对象为起点向下搜索引用的对象,这个时候栈帧出栈了,那么其引用的对象之前已经标记为非垃圾对象,浮动垃圾 下次再收集。针对并发标记,并发清理开始后产生的新对象,通常做法直接当成黑色,本轮不进行清理。这部分对象也可能会变成垃圾,这也算浮动垃圾的一部分

漏标

现在有GC Roots对象是A 这个时候开始并发标记,标记到了B ,因为A的d是空所以A 直接变为黑色。

B开始标记 ,B标记了C为黑色 ,这个时候B为灰色,因为还有b.d还没标记,这个时候程序在走,执行到了a.b.d=null

这个时候垃圾回收器扫描到了b.d已经是null了,不标记了(默认白色). 但是随着代码继续走 a.d=d这个时候d就不是垃圾对象了。

但是因为A已经被标记过了黑色 ,不会再扫描A了 ,那么这个D还是白色

public class ThreeColor {
    public void main2(String[] args) {
        A a = new A(); // GC Roots
        D d = a.b.d; 
        a.b.d = null; 
        a.d = d;
    }
    class A {
        B b = new B();
        D d = null;
    }
    class B {
        C c = new C();
        D d = new D();
    }
    class C {
    }
    class D {
    }
}

 

怎么解决?

浮动垃圾(多标)

这种其实问题不是很大 因为下一次再次扫描的时候发现已经是垃圾对象了 ,直接清理

漏标

漏标会导致被引用的对象当成垃圾误删除,这个严重的bug必须解决 一般解决方案有两种:增量更新和原始快照

增量更新:就是当黑色对象插入新的指向白色对象引用关系时,并发标记的过程中,新增的引用比如 a-->d 放入一个集合存储起来,在重新标记(STW)的时候把A变成灰色对象,重新再扫描一次a.d这个时候它要么灰色标记要么黑色标记。不会是白色 在并发清理的时候就不会被清理。

如果是灰色对象插入新的白色对象的时候 因为它是灰色所以它在并发标记的时候要全部扫描完下面所有的对象才会变成黑色,所以只会是黑色对象插入新的指向

原始快照:每次灰色对象删除白色对象引用的时候把这些引用记录下来,并发结束之后再以这些旧引用重新进行扫描删除指向白色对象引用关系的之前,将这个对象删除的引用记录下来,在并发标记结束之后直接将白色对象变为黑色对象,在下一轮扫描的时候,这个对象可能会是浮动垃圾,直接清理。

原始快照和增量更新的区别

原始快照是在赋值之前放入集合 在并发标记之后将对象变为黑色;

增量更新是在赋值之后放入集合,在重新标记的时候将对象变为黑色

写屏障:也就是类似AOP的概念在赋值的时候在赋值前和后增加一个屏障(一行代码具体实现在HOTSPOT)

CMS:写屏障+增量更新

G1:写屏障+SATB 

为什么G1用SATB 而CMS用增量更新?

自我理解:SATB相对增量更新来说效率更高,因为不需要再重新标记之后再扫描被删除引用的对象,而CMS对增量引用的根对象做深度扫描,G1的很多对象都位于不同region,CMS就老年代一块区域,重新扫描对象的话G1的代价和开销会比CMS高,所以G1选择SATB不深度扫描对象,只是简单标记,宁愿产生一些浮动垃圾,等到下一轮GC在深度扫描

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值