目录
2、write_ref_field_pre/write_ref_field/write_ref_array/write_region
3、static_write_ref_array_pre / static_write_ref_array_post
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
上一篇《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定义,如下:
CardTableModRefBS包含的属性如下:
- const MemRegion _whole_heap; //卡表对应的堆内存区域
- size_t _guard_index; //卡表中最后一个元素的索引
- size_t _last_valid_index;//卡表中最后一个有效元素的索引
- const size_t _page_size; //映射_byte_map时的内存页大小
- size_t _byte_map_size; //_byte_map的字节数,即元素个数
- jbyte* _byte_map; //用于标记的卡表字节数组
- int _cur_covered_regions; //当前的MemRegion在_covered数组的索引
- MemRegion* _covered; //卡表映射的内存区域
- MemRegion* _committed; //与_covered中的MemRegion一一对应,表示对应的卡表项内存区域,当_covered中的元素内存扩容或者缩容时,_committed中对应的卡表项内存会跟着扩容或者缩容
- MemRegion _guard_region;//位于_guard_index的卡表项对应的一个内存页
- jbyte* byte_map_base; //用于计算某个地址映射到卡表字节数组的基地址
- CardArr* _lowest_non_clean; //下列四个数组的长度都跟_covered数组保持一致,为了支持并行的扫描卡表
- size_t* _lowest_non_clean_chunk_size;
- uintptr_t* _lowest_non_clean_base_chunk_index;
- volatile int* _last_LNC_resizing_collection;
CardArr是一个jbyte*的指针的别名,其定义如下:
CardTableModRefBS在ModRefBarrierSet的基础上增加了不少跟卡表本身相关的方法,重点关注BarrierSet接口方法的实现。
2、构造函数和initialize
卡表在整个JVM进程存活期间不会被销毁,所以析构函数没有调用方,构造函数的调用链如下:
从上述调用链可知G1CollectedHeap和GenCollectedHeap的卡表的初始化是通过CardTableRS初始化的,ParallelScavengeHeap没有用到CardTableRS,直接初始化卡表。
查看上述调用方可知,构造函数执行完成后都会调用initialize方法完成初始化,这两者的源码实现如下:
//传递进来的whole_heap实际是整个Java堆
CardTableModRefBS::CardTableModRefBS(MemRegion whole_heap,
int max_covered_regions):
//初始化属性
ModRefBarrierSet(max_covered_regions),
_whole_heap(whole_heap),
_guard_index(0),
_guard_region(),
_last_valid_index(0),
_page_size(os::vm_page_size()),
_byte_map_size(0),
_covered(NULL),
_committed(NULL),
_cur_covered_regions(0),
_byte_map(NULL),
byte_map_base(NULL),
_lowest_non_clean(NULL),
_lowest_non_clean_chunk_size(NULL),
_lowest_non_clean_base_chunk_index(NULL),
_last_LNC_resizing_collection(NULL)
{
_kind = BarrierSet::CardTableModRef;
//校验堆内存的起始地址的低8位必须都是0
assert((uintptr_t(_whole_heap.start()) & (card_size - 1)) == 0, "heap must start at card boundary");
assert((uintptr_t(_whole_heap.end()) & (card_size - 1)) == 0, "heap must end at card boundary");
assert(card_size <= 512, "card_size must be less than 512"); // why?
//ParallelScavengeHeap下传3,GenCollectedHeap下不是一个固定值,G1CollectedHeap下传2
_covered = new MemRegion[_max_covered_regions];
if (_covered == NULL) {
vm_exit_during_initialization("Could not allocate card table covered region set.");
}
}
void CardTableModRefBS::initialize() {
//cards_required用于计算堆内存对应的卡表项的个数
_guard_index = cards_required(_whole_heap.word_size()) - 1;
_last_valid_index = _guard_index - 1;
//计算_byte_map对应的内存块大小
_byte_map_size = compute_byte_map_size();
HeapWord* low_bound = _whole_heap.start();
HeapWord* high_bound = _whole_heap.end();
_cur_covered_regions = 0;
//初始化_committed,跟_covered的数组元素个数一致
_committed = new MemRegion[_max_covered_regions];
if (_committed == NULL) {
vm_exit_during_initialization("Could not allocate card table committed region set.");
}
//_page_size初始化的时候就等于os::vm_page_size()
const size_t rs_align = _page_size == (size_t) os::vm_page_size() ? 0 :
MAX2(_page_size, (size_t) os::vm_allocation_granularity());
//为byte_map申请一段连续内存
ReservedSpace heap_rs(_byte_map_size, rs_align, false);
MemTracker::record_virtual_memory_type((address)heap_rs.base(), mtGC);
os::trace_page_sizes("card table", _guard_index + 1, _guard_index + 1,
_page_size, heap_rs.base(), heap_rs.size());
if (!heap_rs.is_reserved()) {
//申请失败,抛出异常
vm_exit_during_initialization("Could not reserve enough space for the "
"card marking array");
}
//获取基地址,作为_byte_map数组的地址
_byte_map = (jbyte*) heap_rs.base();
//计算从内存地址映射到字节数组元素的基地址
byte_map_base = _byte_map - (uintptr_t(low_bound) >> card_shift);
//校验堆内存的地址范围都在_byte_map支持映射的地址范围内
assert(byte_for(low_bound) == &_byte_map[0], "Checking start of map");
assert(byte_for(high_bound-1) <= &_byte_map[_last_valid_index], "Checking end of map");
//初始化guard_card
jbyte* guard_card = &_byte_map[_guard_index];
uintptr_t guard_page = align_size_down((uintptr_t)guard_card, _page_size);
_guard_region = MemRegion((HeapWord*)guard_page, _page_size);
os::commit_memory_or_exit((char*)guard_page, _page_size, _page_size,
!ExecMem, "card table last card");
*guard_card = last_card;
//初始化4个数组
_lowest_non_clean =
NEW_C_HEAP_ARRAY(CardArr, _max_covered_regions, mtGC);
_lowest_non_clean_chunk_size =
NEW_C_HEAP_ARRAY(size_t, _max_covered_regions, mtGC);
_lowest_non_clean_base_chunk_index =
NEW_C_HEAP_ARRAY(uintptr_t, _max_covered_regions, mtGC);
_last_LNC_resizing_collection =
NEW_C_HEAP_ARRAY(int, _max_covered_regions, mtGC);
if (_lowest_non_clean == NULL
|| _lowest_non_clean_chunk_size == NULL
|| _lowest_non_clean_base_chunk_index == NULL
|| _last_LNC_resizing_collection == NULL)
//内存分配失败抛出异常
vm_exit_during_initialization("couldn't allocate an LNC array.");
for (int i = 0; i < _max_covered_regions; i++) {
//数组元素初始化
_lowest_non_clean[i] = NULL;
_lowest_non_clean_chunk_size[i] = 0;
_last_LNC_resizing_collection[i] = -1;
}
if (TraceCardTableModRefBS) {
gclog_or_tty->print_cr("CardTableModRefBS::CardTableModRefBS: ");
gclog_or_tty->print_cr(" "
" &_byte_map[0]: " INTPTR_FORMAT
" &_byte_map[_last_valid_index]: " INTPTR_FORMAT,
p2i(&_byte_map[0]),
p2i(&_byte_map[_last_valid_index]));
gclog_or_tty->print_cr(" "
" byte_map_base: " INTPTR_FORMAT,
p2i(byte_map_base));
}
}
inline size_t cards_required(size_t covered_words) {
// Add one for a guard card, used to detect errors.
const size_t words = align_size_up(covered_words, card_size_in_words);
return words / card_size_in_words + 1;
}
size_t CardTableModRefBS::compute_byte_map_size()
{
assert(_guard_index == cards_required(_whole_heap.word_size()) - 1,
"unitialized, check declaration order");
assert(_page_size != 0, "unitialized, check declaration order");
const size_t granularity = os::vm_allocation_granularity();
//_guard_index+1相当于卡表项的数量,每个卡表项都是1个字节,总的字节数就是_guard_index+1
//将其向上取整获取实际的字节数
return align_size_up(_guard_index + 1, MAX2(_page_size, granularity));
}
//将某个地址映射到卡表的字节数组元素
jbyte* byte_for(const void* p) const {
//校验这个地址位于堆内存中
assert(_whole_heap.contains(p),
err_msg("Attempt to access p = " PTR_FORMAT " out of bounds of "
" card marking array's _whole_heap = [" PTR_FORMAT "," PTR_FORMAT ")",
p2i(p), p2i(_whole_heap.start()), p2i(_whole_heap.end())));
//此处的计算相当于_byte_map - (uintptr_t(low_bound) >> card_shift)+ (uintptr_t(p) >> card_shift)
jbyte* result = &byte_map_base[uintptr_t(p) >> card_shift];
//校验result没有超过数组的范围
assert(result >= _byte_map && result < _byte_map + _byte_map_size,
"out of bounds accessor for card marking array");
return result;
}
CardTableModRefBS::~CardTableModRefBS() {
//释放各数组
if (_covered) {
delete[] _covered;
_covered = NULL;
}
if (_committed) {
delete[] _committed;
_committed = NULL;
}
if (_lowest_non_clean) {
FREE_C_HEAP_ARRAY(CardArr, _lowest_non_clean, mtGC);
_lowest_non_clean = NULL;
}
if (_lowest_non_clean_chunk_size) {
FREE_C_HEAP_ARRAY(size_t, _lowest_non_clean_chunk_size, mtGC);
_lowest_non_clean_chunk_size = NULL;
}
if (_lowest_non_clean_base_chunk_index) {
FREE_C_HEAP_ARRAY(uintptr_t, _lowest_non_clean_base_chunk_index, mtGC);
_lowest_non_clean_base_chunk_index = NULL;
}
if (_last_LNC_resizing_collection) {
FREE_C_HEAP_ARRAY(int, _last_LNC_resizing_collection, mtGC);
_last_LNC_resizing_collection = NULL;
}
}
3、inline_write_ref_field_pre/inline_write_ref_field/inline_write_region/inline_write_ref_array
上述四个方法就是BarrierSet中内联方法调用的子类方法,其实现都是将某个地址或者一段连续的内存地址对应的卡表项标记为脏的,源码分析如下:
template <class T> inline void inline_write_ref_field_pre(T* field, oop newVal) {}
template <class T> inline void inline_write_ref_field(T* field, oop newVal, bool release) {
//获取该字段的内存地址对应的卡表项
jbyte* byte = byte_for((void*)field);
//将卡表项标记为脏的
if (release) {
// Perform a releasing store if requested.
OrderAccess::release_store((volatile jbyte*) byte, dirty_card);
} else {
*byte = dirty_card;
}
}
void write_ref_array_work(MemRegion mr) {
inline_write_ref_array(mr);
}
inline void inline_write_ref_array(MemRegion mr) {
dirty_MemRegion(mr);
}
void CardTableModRefBS::dirty_MemRegion(MemRegion mr) {
assert((HeapWord*)align_size_down((uintptr_t)mr.start(), HeapWordSize) == mr.start(), "Unaligned start");
assert((HeapWord*)align_size_up ((uintptr_t)mr.end(), HeapWordSize) == mr.end(), "Unaligned end" );
jbyte* cur = byte_for(mr.start());
//last返回MemRegion最后一个字宽的地址
jbyte* last = byte_after(mr.last());
//将MemRegion内存区域对应的所有卡表项都标记为脏的
while (cur < last) {
*cur = dirty_card;
cur++;
}
}
// Mapping from address to card marking array entry
jbyte* byte_for(const void* p) const {
assert(_whole_heap.contains(p),
err_msg("Attempt to access p = " PTR_FORMAT " out of bounds of "
" card marking array's _whole_heap = [" PTR_FORMAT "," PTR_FORMAT ")",
p2i(p), p2i(_whole_heap.start()), p2i(_whole_heap.end())));
jbyte* result = &byte_map_base[uintptr_t(p) >> card_shift];
assert(result >= _byte_map && result < _byte_map + _byte_map_size,
"out of bounds accessor for card marking array");
return result;
}
jbyte* byte_after(const void* p) const {
return byte_for(p) + 1;
}
void write_region_work(MemRegion mr) {
inline_write_region(mr);
}
inline void inline_write_region(MemRegion mr) {
dirty_MemRegion(mr);
}
void CardTableModRefBS::write_ref_field_work(void* field, oop newVal, bool release) {
inline_write_ref_field(field, newVal, release);
}
4、mod_card_iterate /dirty_card_iterate /dirty_card_range_after_reset
这三个方法都是用来查找遍历脏的卡片,mod_card_iterate有两个重载版本,区别在于两者遍历的卡表项范围不同,一个是遍历整个堆内存对应的MemRegion,一个是遍历指定的MemRegion对应的卡表项,遍历的时候都是按照地址降序的顺序遍历,将找到的多个连续的脏的卡表项对应的内存块合并成一个MemRegion交给MemRegionClosure处理。dirty_card_iterate与mod_card_iterate最大的不同是dirty_card_iterate是按照地址升序的方式遍历。dirty_card_range_after_reset跟dirty_card_iterate类似,区别在于dirty_card_range_after_reset支持将找到的脏的卡表项重置成指定的值,并且在找到连续的多个脏的卡表项就返回这些卡表项对应的MemRegion,不继续遍历了。上述4个方法的源码如下:
void mod_card_iterate(MemRegionClosure* cl) {
non_clean_card_iterate_serial(_whole_heap, cl);
}
void mod_card_iterate(MemRegion mr, MemRegionClosure* cl) {
non_clean_card_iterate_serial(mr, cl);
}
//MemRegionClosure通过此方法遍历所有的脏的卡表项,具体的处理逻辑都在MemRegionClosure中
void CardTableModRefBS::non_clean_card_iterate_serial(MemRegion mr,
MemRegionClosure* cl) {
bool is_par = (SharedHeap::heap()->n_par_threads() > 0);
//校验要么不并行,要么两个地方的并行线程数一致
assert(!is_par ||
(SharedHeap::heap()->n_par_threads() ==
SharedHeap::heap()->workers()->active_workers()), "Mismatch");
for (int i = 0; i < _cur_covered_regions; i++) {
//取两个MemRegion的交集区域
MemRegion mri = mr.intersection(_covered[i]);
if (mri.word_size() > 0) {
//获取mri起始地址对应的卡表范围
jbyte* cur_entry = byte_for(mri.last());
jbyte* limit = byte_for(mri.start());
while (cur_entry >= limit) {
jbyte* next_entry = cur_entry - 1;
if (*cur_entry != clean_card) {
size_t non_clean_cards = 1;
//往前按照地址降序遍历,找到紧挨着的同样是脏的卡表项
while (next_entry >= limit && *next_entry != clean_card) {
non_clean_cards++;
cur_entry = next_entry;
next_entry--;
}
//将多个连续的脏的卡表项对应的内存块合并成一个MemRegion
MemRegion cur_cards(addr_for(cur_entry),
non_clean_cards * card_size_in_words);
//取cur_cards与mri的交集,避免根据卡表项反推出来的地址范围超过了原来mri的范围
MemRegion dirty_region = cur_cards.intersection(mri);
通过MemRegionClosure处理脏的卡表项
cl->do_MemRegion(dirty_region);
}
cur_entry = next_entry;
}
}
}
}
//获取卡表项地址对应的内存地址
HeapWord* addr_for(const jbyte* p) const {
assert(p >= _byte_map && p < _byte_map + _byte_map_size,
"out of bounds access to card marking array");
size_t delta = pointer_delta(p, byte_map_base, sizeof(jbyte));
HeapWord* result = (HeapWord*) (delta << card_shift);
assert(_whole_heap.contains(result),
err_msg("Returning result = " PTR_FORMAT " out of bounds of "
" card marking array's _whole_heap = [" PTR_FORMAT "," PTR_FORMAT ")",
p2i(result), p2i(_whole_heap.start()), p2i(_whole_heap.end())));
return result;
}
void CardTableModRefBS::dirty_card_iterate(MemRegion mr,
MemRegionClosure* cl) {
for (int i = 0; i < _cur_covered_regions; i++) {
//取交集
MemRegion mri = mr.intersection(_covered[i]);
if (!mri.is_empty()) {
jbyte *cur_entry, *next_entry, *limit;
//按地址升序的方式遍历卡表项
for (cur_entry = byte_for(mri.start()), limit = byte_for(mri.last());
cur_entry <= limit;
cur_entry = next_entry) {
next_entry = cur_entry + 1;
if (*cur_entry == dirty_card) {
size_t dirty_cards;
//找到多个连续的脏的卡表项
for (dirty_cards = 1;
next_entry <= limit && *next_entry == dirty_card;
dirty_cards++, next_entry++);
//将多个脏的卡表项对应的内存区域合并成一个MemRegion
MemRegion cur_cards(addr_for(cur_entry),
dirty_cards*card_size_in_words);
cl->do_MemRegion(cur_cards);
}
}
}
}
}
MemRegion CardTableModRefBS::dirty_card_range_after_reset(MemRegion mr,
bool reset,
int reset_val) {
for (int i = 0; i < _cur_covered_regions; i++) {
MemRegion mri = mr.intersection(_covered[i]);
if (!mri.is_empty()) {
jbyte* cur_entry, *next_entry, *limit;
for (cur_entry = byte_for(mri.start()), limit = byte_for(mri.last());
cur_entry <= limit;
cur_entry = next_entry) {
next_entry = cur_entry + 1;
if (*cur_entry == dirty_card) {
size_t dirty_cards;
//遍历逻辑同dirty_card_iterate,不同的是支持卡表项的值重置
for (dirty_cards = 1;
next_entry <= limit && *next_entry == dirty_card;
dirty_cards++, next_entry++);
MemRegion cur_cards(addr_for(cur_entry),
dirty_cards*card_size_in_words);
if (reset) {
for (size_t i = 0; i < dirty_cards; i++) {
cur_entry[i] = reset_val;
}
}
//找到连续的多个脏的卡表项就返回,不继续遍历
return cur_cards;
}
}
}
}
//没有找到返回一个空的MemRegion
return MemRegion(mr.end(), mr.end());
}
上述方法的调用链如下:
5、clear /invalidate
clear用于将某个MemRegion对应的卡表项全部置为clean_card,invalidate与之相反,将某个MemRegion对应的卡表项全部置为dirty_card。这两方法的调用链如下:
两者的源码如下:
void CardTableModRefBS::clear(MemRegion mr) {
for (int i = 0; i < _cur_covered_regions; i++) {
//取mr同_covered的交集
MemRegion mri = mr.intersection(_covered[i]);
if (!mri.is_empty()) clear_MemRegion(mri);
}
}
void CardTableModRefBS::clear_MemRegion(MemRegion mr) {
//计算mr对应的卡表项范围
jbyte* cur;
if (mr.start() == _whole_heap.start()) {
cur = byte_for(mr.start());
} else {
assert(mr.start() > _whole_heap.start(), "mr is not covered.");
cur = byte_after(mr.start() - 1);
}
jbyte* last = byte_after(mr.last());
//将范围内的卡表项的值都置为clean_card
memset(cur, clean_card, pointer_delta(last, cur, sizeof(jbyte)));
}
void CardTableModRefBS::invalidate(MemRegion mr, bool whole_heap) {
//校验mr的起始地址经过内存对齐的
assert((HeapWord*)align_size_down((uintptr_t)mr.start(), HeapWordSize) == mr.start(), "Unaligned start");
assert((HeapWord*)align_size_up ((uintptr_t)mr.end(), HeapWordSize) == mr.end(), "Unaligned end" );
for (int i = 0; i < _cur_covered_regions; i++) {
//取交集
MemRegion mri = mr.intersection(_covered[i]);
if (!mri.is_empty()) dirty_MemRegion(mri);
}
}
void CardTableModRefBS::dirty_MemRegion(MemRegion mr) {
assert((HeapWord*)align_size_down((uintptr_t)mr.start(), HeapWordSize) == mr.start(), "Unaligned start");
assert((HeapWord*)align_size_up ((uintptr_t)mr.end(), HeapWordSize) == mr.end(), "Unaligned end" );
jbyte* cur = byte_for(mr.start());
jbyte* last = byte_after(mr.last());
//将MemRegion对应的卡表项都置为dirty_card
while (cur < last) {
*cur = dirty_card;
cur++;
}
}
6、resize_covered_region
resize_covered_region用于调整_covered中MemRegion的内存大小,并配套调整与之对应的表示卡表项内存的_committed中的MemRegion,如果扩容则commit申请新内存,如果缩容则uncommit减少内存。该方法的调用链如下:
该方法的源码如下:
void CardTableModRefBS::resize_covered_region(MemRegion new_region) {
//校验堆内存是否包含指定的内存块new_region
assert(_whole_heap.contains(new_region),
"attempt to cover area not in reserved area");
debug_only(verify_guard();)
// collided is true if the expansion would push into another committed region
debug_only(bool collided = false;)
//根据new_region的基地址找到对应的_covered元素,如果没有找到则创建一个新的
int const ind = find_covering_region_by_base(new_region.start());
MemRegion const old_region = _covered[ind];
assert(old_region.start() == new_region.start(), "just checking");
//如果两个MemRegion大小不同
if (new_region.word_size() != old_region.word_size()) {
// Commit new or uncommit old pages, if necessary.
MemRegion cur_committed = _committed[ind];
//获取ind之前的committed元素end的最大值,正常情况
HeapWord* const max_prev_end = largest_prev_committed_end(ind);
if (max_prev_end > cur_committed.end()) {
//只有cur_committed是在find_covering_region_by_base方法中新添加的,时才会出现进入此分支
//设置成最大值,这是一个初始值
cur_committed.set_end(max_prev_end);
}
//获取new_region终止地址对应的卡表项地址,并做内存对齐
jbyte* const new_end = byte_after(new_region.last());
HeapWord* new_end_aligned =
(HeapWord*) align_size_up((uintptr_t)new_end, _page_size);
assert(new_end_aligned >= (HeapWord*) new_end,
"align up, but less");
//检查其他的committed元素,判断new_end_aligned是否在其范围内,如果在则修改new_end_aligned
int ri = 0;
for (ri = 0; ri < _cur_covered_regions; ri++) {
if (ri != ind) {
if (_committed[ri].contains(new_end_aligned)) {
//如果包含则ri的起始地址肯定大于ind的,即ri对应内存区域在ind的后面
assert(_committed[ri].start() >= _committed[ind].start(),
"New end of committed region is inconsistent");
//将new_end_aligned缩小为ri的起始地址,避免重叠
new_end_aligned = _committed[ri].start();
assert(new_end_aligned >= _committed[ind].start(),
"New end of committed region is before start");
debug_only(collided = true;)
//因为commit元素是按照地址升序排序的,所以只可能出现一个重叠的
break;
}
}
}
HeapWord* new_end_for_commit = new_end_aligned;
DEBUG_ONLY(bool guarded = false;)
if (new_end_for_commit > _guard_region.start()) {
//不能超过_guard_region的内存区域
new_end_for_commit = _guard_region.start();
DEBUG_ONLY(guarded = true;)
}
if (new_end_for_commit > cur_committed.end()) {
//需要扩容,申请新的内存
MemRegion const new_committed =
MemRegion(cur_committed.end(), new_end_for_commit);
assert(!new_committed.is_empty(), "Region should not be empty here");
os::commit_memory_or_exit((char*)new_committed.start(),
new_committed.byte_size(), _page_size,
!ExecMem, "card table expansion");
} else if (new_end_aligned < cur_committed.end()) {
//新的MemRegion就是需要缩容(uncommit)掉的内存区域
//遍历所有_committed元素,确保新的MemRegion不会跟其他_committed元素的内存区域有重叠
MemRegion const uncommit_region =
committed_unique_to_self(ind, MemRegion(new_end_aligned,
cur_committed.end()));
if (!uncommit_region.is_empty()) {
//UseAdaptiveGCBoundary表示能否移动young和old之间的边界,默认为false
//如果在移动young和old之间的边界的时候缩容(uncommit 卡表对应的内存区域)是不安全的
if (!UseAdaptiveGCBoundary) {
if (!os::uncommit_memory((char*)uncommit_region.start(),
uncommit_region.byte_size())) {
// uncommit失败,new_end_aligned重置成原来的
assert(false, "Card table contraction failed");
new_end_aligned = _committed[ind].end();
}
} else {
//UseAdaptiveGCBoundary为true,因为此时uncommit不安全,所以一样将new_end_aligned重置成原来的
new_end_aligned = _committed[ind].end();
}
}
}
//设置end,等同于设置了size
_committed[ind].set_end(new_end_aligned);
// The default of 0 is not necessarily clean cards.
jbyte* entry;
if (old_region.last() < _whole_heap.start()) {
entry = byte_for(_whole_heap.start());
} else {
entry = byte_after(old_region.last());
}
assert(index_for(new_region.last()) < _guard_index,
"The guard card will be overwritten");
jbyte* const end = (jbyte*) new_end_for_commit;
assert((end >= byte_after(new_region.last())) || collided || guarded,
"Expect to be beyond new region unless impacting another region");
if (entry < end) {
//如果entry小于end,则两者之间的卡表项为扩容部分对应的卡表项
//将entry和end之间的卡表项置为clean_card
memset(entry, clean_card, pointer_delta(end, entry, sizeof(jbyte)));
}
}
//修改_covered元素的word_size
_covered[ind].set_word_size(new_region.word_size());
if (TraceCardTableModRefBS) {
//打印Trace日志
gclog_or_tty->print_cr("CardTableModRefBS::resize_covered_region: ");
gclog_or_tty->print_cr(" "
" _covered[%d].start(): " INTPTR_FORMAT
" _covered[%d].last(): " INTPTR_FORMAT,
ind, p2i(_covered[ind].start()),
ind, p2i(_covered[ind].last()));
gclog_or_tty->print_cr(" "
" _committed[%d].start(): " INTPTR_FORMAT
" _committed[%d].last(): " INTPTR_FORMAT,
ind, p2i(_committed[ind].start()),
ind, p2i(_committed[ind].last()));
gclog_or_tty->print_cr(" "
" byte_for(start): " INTPTR_FORMAT
" byte_for(last): " INTPTR_FORMAT,
p2i(byte_for(_covered[ind].start())),
p2i(byte_for(_covered[ind].last())));
gclog_or_tty->print_cr(" "
" addr_for(start): " INTPTR_FORMAT
" addr_for(last): " INTPTR_FORMAT,
p2i(addr_for((jbyte*) _committed[ind].start())),
p2i(addr_for((jbyte*) _committed[ind].last())));
}
debug_only((void) (*byte_for(_covered[ind].last()));)
debug_only(verify_guard();)
}
//根据基地址找到对应的covering_region,如果没有匹配的则创建一个新的
int CardTableModRefBS::find_covering_region_by_base(HeapWord* base) {
int i;
//_covered数组中的MemRegion是按照地址升序来的,所以找到一个基地址大于base的就可以停止查找了
for (i = 0; i < _cur_covered_regions; i++) {
if (_covered[i].start() == base) return i;
if (_covered[i].start() > base) break;
}
//没有对应的MemRegion则创建一个新的,只有两种情形,要么所有的_covered MemRegion的基地址小于start,i就等于_cur_covered_regions
//要么有一个_covered MemRegion的基地址大于base,i就小于_cur_covered_regions
assert(_cur_covered_regions < _max_covered_regions,
"too many covered regions");
//把i之后数组元素往后挪一个,从而让新的元素放到i的位置上,如果i等于_cur_covered_regions则不处理
for (int j = _cur_covered_regions; j > i; j--) {
_covered[j] = _covered[j-1];
_committed[j] = _committed[j-1];
}
int res = i;
//初始化新的_covered和_committed数组元素
_cur_covered_regions++;
_covered[res].set_start(base);
_covered[res].set_word_size(0);
//计算base对应的卡表项地址,并做内存对齐
jbyte* ct_start = byte_for(base);
uintptr_t ct_start_aligned = align_size_down((uintptr_t)ct_start, _page_size);
_committed[res].set_start((HeapWord*)ct_start_aligned);
_committed[res].set_word_size(0);
return res;
}
//获取ind之前的_committed元素的最大的end地址
HeapWord* CardTableModRefBS::largest_prev_committed_end(int ind) const {
HeapWord* max_end = NULL;
for (int j = 0; j < ind; j++) {
HeapWord* this_end = _committed[j].end();
if (this_end > max_end) max_end = this_end;
}
return max_end;
}
//遍历所有_committed元素,保证mr是唯一的,不会跟其他_committed元素的内存区域有重叠
MemRegion CardTableModRefBS::committed_unique_to_self(int self,
MemRegion mr) const {
MemRegion result = mr;
for (int r = 0; r < _cur_covered_regions; r += 1) {
if (r != self) {
//minus表示取result区域减去_committed[r]区域的剩余区域
result = result.minus(_committed[r]);
}
}
// Never include the guard page.
result = result.minus(_guard_region);
return result;
}
来源:CSDN
作者:孙大圣666
链接:https://blog.csdn.net/qq_31865983/article/details/103667290