HoptSpot的算法细节实现(三)

写屏障

上面我们解决了如何利用记忆集来缩减GC Roots扫面范围的问题,但是还没有解决卡表元素如何维护的问题,例如:它何时变脏、谁把他们变脏。

卡表元素何时变脏的答案是很明确的——有其他分代区域中对象引用了本区域对象时,其对应的卡表元素就应该变脏,变脏的时间节点原则上应该发生在引用类型字段赋值那一刻。

但是如何变脏,即如何在对象赋值那一刻去更新维护卡表?

在HotSpot虚拟机里面通过写屏障(Write Barrier)技术维护卡表的状态。写屏障可以看作在虚拟机层面对“引用类型字段赋值”这个动作的AOP切面,在引用对象赋值时会产生一个环形(Around)通知,供程序执行额外的动作,即赋值的前后都在写屏障的覆盖范围内。在赋值前的部分的写屏障叫做写前屏障(Pre-Write Barrier),在赋值Post-写后屏障(Post-Write Barrier)。

下面这段代码为应用写后屏障更新卡表

void oop_field+store(oop* field, oop new_value){
       //引用字段赋值操作
        *field=new_value;
        //写后屏障,在这里完成卡表状态更新
        post_write_barrier(field,new_value);
}

 应用写屏障后,虚拟机就会为所有赋值操作生成相应的指令,一旦收集器在写屏障中增加了更新卡表操作,无论更新的是不是老年代对新生代对象的引用,每次只要只要对引用进行更新,就会产生额外的开销,不过这个开销与Minor GC时扫描整个老年代的代价相比还是低很多。

除了写屏障的开销外,卡表在高并发场景下还面临着“伪共享”(False Sharing)问题。

现代中央处理器的缓存系统中是以缓存行(Cache Line)为单位存储的,当线程修改互相独立的变量时,如果这些变量恰好共享一个缓存行,就会彼此影响(写回、无效化或者同步)而导致性能降低,这就是伪共享问题。

为了解决伪共享问题,一种简单的解决方案是不采用无条件的写屏障,而是先检查卡表标记,只有当该卡表元素未被标记过时,才将其标记为变脏,即将卡表更新的逻辑变为以下代码:

if(CARD_TABLE[this address >> 9]!=0)
    CARD_TABLE[this address >> 9]!=0;

 并发的可达性分析

在根节点枚举这个步骤中,由于GC Roots相比起整个Java堆中全部的对象毕竟还是少数,且在各种优化技巧(如OopMap)的加持下,它带来的停顿已经非常短暂且相对固定(不随堆容量而增长)的了。可从GC Roots再继续往下遍历对象图,这一步骤的停顿时间就必定会与Java堆容量直接成正比例关系了:堆越大,存储对象越多,对象图结构越复杂,要标记更多对象而产生的停顿时间自然就更长,这听起来是理所当然的事情。

要知道包含“标记”阶段是所有追踪式垃圾收集算法的共同特征,如果这个阶段随着堆变大而等比例增加停顿时间,其影响几乎会波及所有的垃圾收集器,同理,如果减少这部分时间,带来的影响也是系统性的。

想要解决或者降低用户线程的停顿,就要先搞清楚为什么必须在一个能保障一致性的快照上才能进行对象图遍历?为了解释这个问题,我们引入三色标记(Tri-color Marking)作为工具来辅助推导。

  • 白色:表示对象尚未被垃圾收集器访问过;
  • 黑色:表示对象已经被垃圾收集器访问过,且这个对象的所有引用都已经扫描过;
  • 灰色:表示对象已经被垃圾收集器访问过,但是这个对象上至少存在一个引用还没有被扫描过。

下图为并发出现“对象消失”问题示意

 

Wilson于1994年在理论上证明了,当且仅当以下两个条件满足时,会产生“对象消失”的问题,即原本应该是黑色的对象被误标为白色:

  • 赋值器插入了一条或者多条从黑色对象到白色对象的新引用;
  • 赋值器删除了全部从灰色对象到该白色对象的直接引用或者间接引用。

因此要解决并发扫描时的对象消失问题,只需要破化以上两个条件的其中一个即可。因此产生两种解决方案

  • 增量更新(Incremental Update)
  • 原始快照(Snapshot At The Beginning,SATB)

增量更新破坏的是第一个条件,当黑色对象插入新的指向白色对象的引用关系时,就将这个新插入的引用记录下来,等并发扫描结束之后,再将这些记录过的引用关系中的黑色对象为根,重新扫描一次。

原始快照破化的是第二个条件,当灰色对象要删除指向白色对象的引用关系时,就将这个要删除的引用记录下来,在并发扫描结束后,再将这些记录过的引用关系中的灰色对象为根,重新扫描一次

以上无论是对引用关系记录的插入还是删除,虚拟机的记录操作都是通过写屏障实现的,且以上两种方案在垃圾收集器中都有实际使用如:CMS是基于增量更新来做并发标记;G1、Shenandoah则是使用原始快照来实现的。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值