Hotspot 垃圾回收之BarrierSet(一) 源码解析

深入解析Hotspot中BarrierSet的作用及其实现,重点介绍CardTableModRefBS类,包括其构造、核心方法实现及卡表项遍历机制。探讨其在垃圾回收过程中的关键角色。

目录

一、BarrierSet

1、定义

2、write_ref_field_pre/write_ref_field/write_ref_array/write_region

3、static_write_ref_array_pre / static_write_ref_array_post

二、CardTableModRefBS

1、定义

2、构造函数和initialize

3、inline_write_ref_field_pre/inline_write_ref_field/inline_write_region/inline_write_ref_array

4、mod_card_iterate /dirty_card_iterate /dirty_card_range_after_reset

5、clear /invalidate

6、resize_covered_region


      上一篇《Hotspot 垃圾回收之CollectedHeap 源码解析》中讲解CollectedHeap的定义时提到了一个BarrierSet类,该类的具体用途没有注释说明,但是该属性的调用方很多,本篇博客就详细探讨这个神秘的BarrierSet的实现和使用。

一、BarrierSet

1、定义

    BarrierSet表示一个数据读写动作的栅栏,跟高速缓存中用来在不同CPU之间同步数据的的Barrier(内存屏障)完全不同,BarrierSet的功能类似于一个拦截器,在读写动作实际作用于内存前执行某些前置或者后置动作,其定义在hotspot src/share/vm/memory/barrierSet.hpp中。BarrierSet是一个抽象类,其类继承关系如下:

 BarrierSet定义了一个枚举Name来描述不同类型的子类,如下:

 BarrierSet定义的属性就两个,如下:

 BarrierSet定义了几个虚方法来描述BarrierSet子类支持的动作,如下:

方法名中的ref表示引用类型的数据,prim表示基本类型的数据,has_read_ref_barrier表示该BarrierSet是在读取引用类型数据时执行的,has_write_ref_barrier表示该BarrierSet是在写入引用类型数据时执行的,has_write_ref_pre_barrier表示该BarrierSet是在写入引用类型数据前预先执行的。

与之功能类似的还有如下虚方法:

即BarrierSet支持的读写数据除了对象字段属性还有数组,MemRegion类型的数据,其定义的方法也可以按照数据类型整体上分为三类:

  • 读写对象属性类型的数据,如read_ref_field,read_prim_field,write_ref_field,write_prim_field
  • 读写数组类型的数据,如read_ref_array,read_prim_array,write_ref_array_pre,write_ref_array_pre,write_prim_array,write_ref_array
  • 读写MemRegion类型的数据,如read_region,write_region

BarrierSet定义的方法都是虚方法,重点关注其基于虚方法实现的内联方法和静态方法的实现。

2、write_ref_field_pre/write_ref_field/write_ref_array/write_region

      因为BarrierSet的子类只有支持写屏障的类型,所以BarrierSet基于子类的虚方法提供了上述内联方法的默认实现,然后重点关注对应的子类虚方法实现即可。其实现如下:

template <class T> void BarrierSet::write_ref_field_pre(T* field, oop new_val) {
  if (kind() == CardTableModRef) {
    ((CardTableModRefBS*)this)->inline_write_ref_field_pre(field, new_val);
  } else {
    write_ref_field_pre_work(field, new_val);
  }
}

void BarrierSet::write_ref_field(void* field, oop new_val, bool release) {
  if (kind() == CardTableModRef) {
    ((CardTableModRefBS*)this)->inline_write_ref_field(field, new_val, release);
  } else {
    write_ref_field_work(field, new_val, release);
  }
}


//start是准备写入数组的起始元素的地址,count是写入的元素个数
void BarrierSet::write_ref_array(HeapWord* start, size_t count) {
  assert(count <= (size_t)max_intx, "count too large");
  HeapWord* end = (HeapWord*)((char*)start + (count*heapOopSize));
  //在没有开启指针压缩的场景下,start和end都是经过对齐的,start等于aligned_start,end等于aligned_end
  //开启指针压缩了则不一定
  HeapWord* aligned_start = (HeapWord*)align_size_down((uintptr_t)start, HeapWordSize);
  HeapWord* aligned_end   = (HeapWord*)align_size_up  ((uintptr_t)end,   HeapWordSize);
  // If compressed oops were not being used, these should already be aligned
  assert(UseCompressedOops || (aligned_start == start && aligned_end == end),
         "Expected heap word alignment of start and end");
  
  write_ref_array_work(MemRegion(aligned_start, aligned_end));
}


void BarrierSet::write_region(MemRegion mr) {
  if (kind() == CardTableModRef) {
    ((CardTableModRefBS*)this)->inline_write_region(mr);
  } else {
    write_region_work(mr);
  }
}

上述四个方法的调用链如下:

 

 

上述调用链其实并不完整,还有一些典型场景如修改对象字段属性时触发的不在列表中,后面的博客会挑选典型的场景说明其应用。

3、static_write_ref_array_pre / static_write_ref_array_post

     这两方法是BarrierSet对外的仅有的两个static方法,同样是基于虚方法实现,如下:

void BarrierSet::static_write_ref_array_pre(HeapWord* start, size_t count) {
  assert(count <= (size_t)max_intx, "count too large");
  if (UseCompressedOops) {
    Universe::heap()->barrier_set()->write_ref_array_pre((narrowOop*)start, (int)count, false);
  } else {
    Universe::heap()->barrier_set()->write_ref_array_pre(      (oop*)start, (int)count, false);
  }
}

// count is number of array elements being written
void BarrierSet::static_write_ref_array_post(HeapWord* start, size_t count) {
  // simply delegate to instance method
  Universe::heap()->barrier_set()->write_ref_array(start, count);
}

这两方法的调用链一致,如下:

二、CardTableModRefBS

1、定义

      ModRefBarrierSet继承自BarrierSet,表示一个只支持引用字段类型修改的BarrierSet,ModRefBarrierSet中用来描述其支持的动作类型的方法的实现如下:

ModRefBarrierSet在同目录的modRefBarrierSet.hpp中,ModRefBarrierSet提供了BarrierSet中定义的虚方法的空实现,同时新增了两个虚方法。

     CardTableModRefBS继承自ModRefBarrierSet,表示一个在卡表(Card Table)下使用的ModRefBarrierSet,其补充的描述其支持的动作类型的方法的实现如下:

 

在CardTableModRefBS当前的实现下,当某个对象o的引用类型字段发生了修改,包含了对象o的对象头的卡表项被标记为脏的,而不是包含了这个被修改的字段的卡表项;当对象数组的某个元素发生修改了,只有包含了这个被修改元素的卡表项被标记为脏的。用来遍历查找脏的卡表项的MemRegionClosures的实现必须考虑上述问题。

卡表项的取值用枚举CardValues表示,其定义如下:

其中dirty_card和precleaned_card被认为是脏的,参考card_is_dirty_wrt_gen_iter方法的实现,如下:

每个卡表项对应的内存块card_size的大小通过枚举SomePublicConstants定义,如下:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值