hotspot算法细节实现

根节点枚举

        垃圾回收器在根节点枚举(查找Gc Roots引用链)这一步都需要暂停用户线程。保证整个枚举过程中子系统看起来就像冻结在某个时间点,不会出现根节点集合及引用过程还在不断变化情况。虚拟机不需要一个不漏的查完所有执行上下文及引用位置。在hotspot中采用OopMap的数据结构,一旦类加载动作完成后hotspot就会把对象内偏移量上的类型数据计算出来,在即时编译过程中,也会在特定的位置记录下栈里的和寄存器哪里的位置是引用,这样收集器扫面时就可以直接获得这些信息,不需要一个不漏从Gc Roots查找。

安全点

        hotspot特定位置生成OopMap的位置称为安全点,强制用户线程必须到达安全点后才可以进行垃圾收集。安全点以是否让程序具有长时间运行的特征来进行选取。例如:安全方法调用、循环跳转、异常跳转等都属于指令序列服用,这些地方会产生安全点。

安全点线程停顿的两种方案

        抢先式中断:不需要线程执行代码配合,垃圾回收时对用户线程进行暂停,如果不在安全点则恢复用户线程,运行再次执行中断知道跑到安全点上。

        主动式中断:垃圾回收器需要中断线程时,不主动对线程进行操作。设置一个标志位,各个线程轮询此标志位,如果标志位为true则各线程再各自最近的安全点进行挂起。

安全区域

        安全点机制保证了程序执行时可以在较短的时间遇到垃圾回收安全点,可当程序不执行时(没有分配处理器时间 例如:程序sleep或blocked状态),此时程序无法相应中断无法走段安全点挂起自己。

        引入安全区域解决程序无法相应响应中断情况,安全区域指的是在这以区域内引用关系不会发生变化,因此在这个区域的任何地方开始垃圾收集都是安全的。用户线程在进入安全区域后会进行标识自身,当线程离开安全区域时会检查自身是否完成Gc Roots枚举,如果完成则继续执行,如果未完成则挂起等待,知道完成Gc Roots枚举。

记忆集与卡表

        此功能为解决新生代与老年代跨代引用问题,垃圾回收器在新生代中创建记忆集的数据结构避免把全部老年代加入Gc Roots的扫描范围。不仅仅在分代垃圾回收期存在跨代引用任何设计分区的垃圾回收期都存在跨引用问题(G1、ZGC、Shenandoah)。

        记忆集时一种记录从非收集区域指向收集区域的指针抽象数据集合。在实现中收集器只记录判断一块非收集区域是否存在指向收集区域的指针,不单独为每一个对象设计收集器。

        精度选择:

        字节精度:每个记录精确到一个机器字长,包含跨代指针

        对象精度:每个记录精确到一个对象,该对象由字段含有跨代指针

        卡精度:每个精度精确到一块区域,该区域内有对象含有跨代指针

        卡表是记忆集的一种具体实现,hotspot中卡表是一个字节数组,字节数组中每一个元素对应标识一块内存区域,这块内存被成为卡页,一般卡页为2的n次幂的字节数,hotspot中为9次幂(512字节),例如CARD_TABLE起始地址对应的内存区域为0x0000~0x01FF。当一个卡页中只要有一个对象存在跨代引用则将起CARD_TABL标识为置1,表示数据变脏。在垃圾回收时将脏数据块加入Gc Roots中一并扫描。

CARD_TABLE [this address >> 9] = 0;

写屏障

        为解决维护卡表问题,解释执行时虚拟机负责每条字节码指令的执行,可充分介入卡表的维护,而在编译后的字节码运行中需要找到一种收到维护卡表。写屏障可看作虚拟机层面对字段赋值的AOP切面,在引用对象赋值时产生环形切面,赋值前后均在写屏障范围内,在G1垃圾回收期出现前大部分收集器只采用写后屏障。

void oop_field_store(oop* field,oop new_value){

    *field = new_value;//引用赋值
    post_write_barrier(field,new_value);//卡表更新

}

        伪共享:在并发的条件下多个线程同时更新卡表会产生伪共享问题,Jdk7后hotspot虚拟机增加参数 -XX: +UserCondCardMark用来解决是否开启在卡表更新前进行一次判断,若有则不进行更新。开启后会增加一次额外的开销,是否开启两种情况各有损耗,应根据实际运行情况进行测试权衡。

并发可达性分析

        为降低Gc Roots枚举暂停用户线程时间引入可达性分析。

        三色标记 

        白色:表示对象尚未被垃圾回收器访问过,可达性算法刚开始阶段所有对象均为白色,可达性分析接收后仍为白色的对象表示不可达。

        黑色:表示对象已经被垃圾回收期访问过,且这个对象的每一个引用均被扫描过,安全存活。如果有其他对象指向黑色对象,无需重新扫描,黑色对象不可不经过灰色对象直接指向白色对象。

        灰色:表示对象已经被垃圾回收器访问过,但这个对象至少存在一个引用还未被扫描。

详细的三色标记可参考此文章:https://blog.youkuaiyun.com/huangzhilin2015/article/details/115282572

        对象消失问题:原本应该是黑色的对象被误标为白色

        Wilson在1994年理论证明,当且仅当以下两种情况满足时,会产生对象小时问题

        1.赋值器插入了一条或多条从黑色对象到白色对象的新引用

        2.赋值器删除了全部从灰色对象到该白色对象的直接或间接引用

        破坏两个条件任意一个即可解决对象消失问题

        解决方案

        增量更新:破坏条件1,当黑色对象插入新的指向白色对象引用时,记录该引用,待扫描结束后将这些记录过关系的黑色对象作为Gc Roots重新进行扫描。可简化理解为当黑色对象插入白色对象引用后将变为灰色对象。

        原始快照:破坏条件2,当灰色对象删除指向白色对象引用时,记录删除引用,在扫描结束后将记录过关系的灰色对象为根重新扫描一次。可简化理解为无论引用关系是否删除,都将按照扫描一刻的对象图快照来搜索。

         

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值