G1 中的内存分区引用 RSet
在G1回收对象时,会根据分区之间的引用关系快速定位到引用者
比如一个老生代分区有一个新生区的对象引用了,即
young.field = old;
则old对象对应的Rset中会标记young所在分区的位置
找到分区后再寻找分区内引用old对象的young对象
管理引用通过add_reference函数
void OtherRegionsTable::add_reference(OopOrNarrowOopStar from, int tid) {
uint cur_hrm_ind = hr()->hrm_index();//current heap region index
int from_card = (int)(uintptr_t(from)>>CardTableModeRefBS::card_shift);//Rset分区?
if (FromCardCache::contains_or_replace((uint)tid, cur_hrm_index, from_card)) {
return;//卡表缓存
}
HeapRegion* from_hr = _g1h->heap_region_containing_raw(from);
RegionIdx_t from_hrm_ind = (RegionIdx_t) from_hr->hrm_index();
if (_coarse_map.at(from_hrm_ind)) {
return;
}
//添加prt引用关系到rset中
size_t ind = from_hrm_ind & _mod_max_fine_entries_mask;
PerRegionTable* prt = find_region_table(ind, from_hr);//rset
if (prt == NULL) {
MutexLockerEx x(...);//加锁,可能有多个线程同时访问一个分区的Rset
prt = find_region_table(ind, from_hr);
if (prt == NULL) {
//使用稀疏矩阵存储关系
uintptr_t from_hr_bot_card_index = uintptr_t(from_hr->bottom())
>>CardTableModeRefBS::card_shift;
CardIdx_t card_index = from_card - from_hr_bot_card_index;
//...
//细粒度卡表满了,删除所有prt,放入粗粒度卡表,即针对分区的bitmap
if(_n_fine_entries == _max_fine_entries) {
prt = delete_region_table();
prt->init(from_hr, false);
} else {
//分配稀疏矩阵空间
prt = PerRegionTable::alloc(from_hr);
link_to_all(prt);
}
PerRegionTable* first_prt = _fine_grain_regions[ind];
prt->set_collision_list_next(first_prt);
_fine_grain_regions[ind] = prt;
_n_fine_entries++;
//稀疏矩阵的数据添加至prt卡表
//...
}
}
prt->add_reference(from);
}
RSet记录引用者的地址,但实际上可以有几种选择
bitmap记录分区,稀疏矩阵记录地址,prt记录HeapRegion其实地址加上对应的分区引用位图