JVM学习之七---底层三色标记算法

垃圾收集底层算法实现

三色标记
在并发标记的过程中,因为标记期间应用程序还继续跑,对象间的引用可能发生变化,多标和漏标的情况就有可能发生。

  • 黑色:表示对象已经被垃圾收集器访问过,且这个对象的所有引用都已经扫描过。黑色的对象代表已经扫描过,它是安全存活的,如果有其他对象引用指向了黑色对象,无须重新扫描一遍。黑色对象不可能直接指向某个白色对象。
  • 灰色:表示对象已经被垃圾收集器访问过,但这个对象只是存在一个引用还没有被扫描过。
  • 白色:表示对象尚未被垃圾收集器访问过。显然在可达性分析刚刚开始的阶段,所有的对象都是白色的,若在分析结束的阶段,仍然是白色的对象,即代表不可达。
public class ThreeColorRemark {
    public static void main(String[] args) {
        A a = new A();//开始做并发标记
        D d = a.b.d; // 1.读
        a.b.d = null; // 2.写
        a.d = d; // 3.写
    }
}

class A {
    B b = new B();
    D d = null;
}

class B {
    C c = new C();
    D d = new D();
}

class C {
}

class D {
}

在这里插入图片描述
多标-浮动垃圾
在并发标记过程中,如果由于方法运行结束导致部分局部变量(gcroot)被销毁,这个GCRoot引用的对象之前又被扫描过(被标记为非垃圾对象),那么本轮GC不会回收这部分的内存。这部分本应该回收但是没有回收到内存中,被称之为"浮动垃圾"。浮动垃圾并不会影响垃圾回收的正确性,只是需要等到下一轮垃圾回收中才能被清除。

漏标-读写屏障
漏标会导致被引用的对象当成垃圾误删除,这是严重的bug,必须解决。解决方案有:增量更新和原始快照(SATB)
增量新增:就是当黑色对象插入新的指向白色对象的引用关系时,就将这个新插入的引用记录下来,等并发扫描结束后,再将这些记录过的引用关系中的黑色对象为跟,重新扫描一次。可以简化理解为:黑色对象一旦插入新的指向白色对象引用后,它就变回灰色对象了。
原始快照:就是当灰色对象要删除指向白色对象的引用关系时,就将这个要删除的引用记录下拉,在并发扫描结束之后,再将这些记录过的引用关系中的灰色对象为跟,重新扫描一次,这样就能扫描到白色的对象,将白色对象直接标记为黑色(目的就是让这种对象在本轮gc清理中存活下来,待下一轮gc的时候重新扫描,这个对象也有可能是浮动垃圾)。
以上物料是对象引用关系记录的插入还是删除,虚拟机的记录操作都是通过写屏障实现的。

  • CMS:写屏障+增量更新
  • G1,Shenandoah:写屏障+SATB
  • ZGC:读写障

为什么G1用SATB?CMS用增量更新?
SATB相对增量更新效率会更高,因为不需要重新标记阶段再次深度扫描被删除引用对象,而CMS对增量引用的跟对象会做深度扫描,G1因为很多对象都位于不同的region,CMS就一块老年代区域,重新深度扫描对象的话G1的代码会比CMS高。

记忆集与卡表
在新生代做GCRoots 可达性扫描过程中可能会碰到跨代引用的对象,这种如果又去对老年代再去扫描效率太低。为此,在新生代可以引入记录集的数据结构,避免把整个老年代加入GCRoots扫描范围。事实上并不是新生代,老年代之间才有跨代引用的问题,所有涉及部分区域收集行为的垃圾收集器,典型的如G1都会面临相同的问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

virtuousOne

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值