目录
1、block_size / block_size_no_stall / block_size_nopar
2、oop_iterate / object_iterate / safe_object_iterate /object_iterate_mem / object_iterate_careful_m
3、save_marks / promote / oop_since_save_marks_iterate
4、forward / prepare_for_compaction / adjust_pointers / compact / reset_after_compaction
5、beginSweepFLCensus / endSweepFLCensus
本篇博客继续上一篇《Hotspot 垃圾回收之CompactibleFreeListSpace(二) 源码解析》讲解CompactibleFreeListSpace的其他关键方法的实现。
1、block_size / block_size_no_stall / block_size_nopar
这三个方法都是用来获取某个地址p对应的内存块的大小,要求p是内存块的起始地址。三个方法的实现核心是一样的,如果是空闲的FreeChunk则获取FreeChunk的大小,否则将其作为对象oop,根据Klass获取oop对应的内存块的大小。区别在于block_size / block_size_no_stall都是并发情形下调用的,会将p强转成volatile变量,会通过while循环不断尝试;block_size_nopar是在非并发情形下调用的,不会将p强转成volatile变量,也没有while循环。block_size_no_stall相比block_size多了一步,当Klass为NULL时通过CMSCollector::block_size_if_printezis_bits方法获取内存块大小,一次循环完成,而此时block_size会多次循环。这三个方法的调用链如下:
其实现如下:
size_t CompactibleFreeListSpace::block_size(const HeapWord* p) const {
NOT_PRODUCT(verify_objects_initialized());
//每次读取p时都需将其转换成volatile变量,从而可以保证CPU能够及时获取对p的修改
while (true) {
// We must do this until we get a consistent view of the object.
if (FreeChunk::indicatesFreeChunk(p)) {
//如果p是一个空闲的FreeChunk
volatile FreeChunk* fc = (volatile FreeChunk*)p;
size_t res = fc->size();
//强制CPU再一次读取指针p
OrderAccess::acquire();
//再次检查p是否是一个一个空闲的FreeChunk,如果是则返回res,如果不是则通过下一次循环进入下面的分支中
if (FreeChunk::indicatesFreeChunk(p)) {
assert(res != 0, "Block size should not be 0");
return res;
}
} else {
//如果p不是一个空闲的FreeChunk,即是一个对象,获取对应的Klass
Klass* k = ((volatile oopDesc*)p)->klass_or_null();
if (k != NULL) {
assert(k->is_klass(), "Should really be klass oop.");
oop o = (oop)p;
assert(o->is_oop(true /* ignore mark word */), "Should be an oop.");
//强制CPU再一次读取指针p
OrderAccess::acquire();
//根据Klass获取对象大小
size_t res = o->size_given_klass(k);
//将res做内存对齐
res = adjustObjectSize(res);
assert(res != 0, "Block size should not be 0");
return res;
}
}
}
}
inline void OrderAccess::acquire() {
volatile intptr_t local_dummy;
#ifdef AMD64
__asm__ volatile ("movq 0(%%rsp), %0" : "=r" (local_dummy) : : "memory");
#else
__asm__ volatile ("movl 0(%%esp),%0" : "=r" (local_dummy) : : "memory");
#endif // AMD64
}
size_t CompactibleFreeListSpace::block_size_no_stall(HeapWord* p,
const CMSCollector* c)
const {
assert(MemRegion(bottom(), end()).contains(p), "p not in space");
DEBUG_ONLY(uint loops = 0;)
while (true) {
//如果p是一个空闲的FreeChunk
if (FreeChunk::indicatesFreeChunk(p)) {
volatile FreeChunk* fc = (volatile FreeChunk*)p;
size_t res = fc->size();
OrderAccess::acquire();
if (FreeChunk::indicatesFreeChunk(p)) {
assert(res != 0, "Block size should not be 0");
assert(loops == 0, "Should be 0");
return res;
}
} else {
//如果p不是一个空闲的FreeChunk,即是一个对象,获取对应的Klass
Klass* k = ((volatile oopDesc*)p)->klass_or_null();
if (k != NULL) {
assert(k->is_klass(), "Should really be klass oop.");
oop o = (oop)p;
assert(o->is_oop(), "Should be an oop");
OrderAccess::acquire();
size_t res = o->size_given_klass(k);
res = adjustObjectSize(res);
assert(res != 0, "Block size should not be 0");
return res;
} else {
// 多了一步,当Klass为null时通过P-bits获取内存块大小,CMSCollector通过一个markBitMap维护了各内存块的大小
return c->block_size_if_printezis_bits(p);
}
}
assert(loops == 0, "Can loop at most once");
DEBUG_ONLY(loops++;)
}
}
//非并发场景下调用,不会将p强转成volatile变量
size_t CompactibleFreeListSpace::block_size_nopar(const HeapWord* p) const {
NOT_PRODUCT(verify_objects_initialized());
assert(MemRegion(bottom(), end()).contains(p), "p not in space");
FreeChunk* fc = (FreeChunk*)p;
if (fc->is_free()) {
return fc->size();
} else {
//不校验klass是否为空,也不做循环
assert(oop(p)->is_oop(true), "Should be an oop");
return adjustObjectSize(oop(p)->size());
}
}
2、oop_iterate / object_iterate / safe_object_iterate /object_iterate_mem / object_iterate_careful_m
oop_iterate是遍历当前Space包含的oop所引用的所有其他oop,object_iterate开头的几个方法是遍历当前Space包含的oop本身,其实现基本相同,如下:
void CompactibleFreeListSpace::oop_iterate(ExtendedOopClosure* cl) {
assert_lock_strong(freelistLock());
HeapWord *cur, *limit;
size_t curSize;
//从bottom开始遍历整个Space
for (cur = bottom(), limit = end(); cur < limit;
cur += curSize) {
//获取内存块的大小
curSize = block_size(cur);
if (block_is_obj(cur)) {
//遍历oop所有引用类型属性对应的oop
oop(cur)->oop_iterate(cl);
}
}
}
bool CompactibleFreeListSpace::block_is_obj(const HeapWord* p) const {
FreeChunk* fc = (FreeChunk*)p;
assert(is_in_reserved(p), "Should be in space");
//如果是空闲的FreeChunk
if (FreeChunk::indicatesFreeChunk(p)) return false;
Klass* k = oop(p)->klass_or_null();
if (k != NULL) {
//如果Klass不为NULL
assert(oop(p)->is_oop(true), "Should be an oop");
return true;
} else {
return false; // Was not an object at the start of collection.
}
}
//同oop_iterate,不过遍历的是Space本身包含的对象,而非Space本身包含的对象所引用的对象
void CompactibleFreeListSpace::object_iterate(ObjectClosure* blk) {
assert_lock_strong(freelistLock());
NOT_PRODUCT(verify_objects_initialized());
HeapWord *cur, *limit;
size_t curSize;
for (cur = bottom(), limit = end(); cur < limit;
cur += curSize) {
curSize = block_size(cur);
if (block_is_obj(cur)) {
blk->do_object(oop(cur));
}
}
}
//跟object_iterate相比多了一个obj_is_alive的判断,只遍历存活的对象
void CompactibleFreeListSpace::safe_object_iterate(ObjectClosure* blk) {
assert_lock_strong(freelistLock());
NOT_PRODUCT(verify_objects_initialized());
HeapWord *cur, *limit;
size_t curSize;
for (cur = bottom(), limit = end(); cur < limit;
cur += curSize) {
curSize = block_size(cur);
if (block_is_obj(cur) && obj_is_alive(cur)) {
blk->do_object(oop(cur));
}
}
}
bool CompactibleFreeListSpace::obj_is_alive(const HeapWord* p) const {
assert(SafepointSynchronize::is_at_safepoint() || !is_init_completed(),
"Else races are possible");
assert(block_is_obj(p), "The address should point to an object");
//Sweeping表示正在执行清理,已经完成对象标记了
if (_collector->abstract_state() == CMSCollector::Sweeping) {
CMSBitMap* live_map = _collector->markBitMap();
//通过CMSBitMap判断对象是否是存活对象
return live_map->par_isMarked((HeapWord*) p);
}
return true;
}
void CompactibleFreeListSpace::object_iterate_mem(MemRegion mr,
UpwardsObjectClosure* cl) {
assert_locked(freelistLock());
NOT_PRODUCT(verify_objects_initialized());
assert(!mr.is_empty(), "Should be non-empty");
//校验mr在当前Space的内存区域范围内
assert(MemRegion(bottom(), end()).contains(mr),
"Should be within used space");
//获取最近一次遍历的对象的地址,如果大于end地址,说明Space中的对象都已经遍历过了
HeapWord* prev = cl->previous(); // max address from last time
if (prev >= mr.end()) { // nothing to do
return;
}
bool last_was_obj_array = false;
HeapWord *blk_start_addr, *region_start_addr;
if (prev > mr.start()) {
//mr中有部分对象已经遍历过了
region_start_addr = prev;
blk_start_addr = prev;
assert((BlockOffsetArrayUseUnallocatedBlock &&
(!is_in(prev))) ||
(blk_start_addr == block_start(region_start_addr)), "invariant");
} else {
region_start_addr = mr.start();
//获取mr.start对应的内存块的起始地址
blk_start_addr = block_start(region_start_addr);
}
HeapWord* region_end_addr = mr.end();
MemRegion derived_mr(region_start_addr, region_end_addr);
//遍历blk_start_addr到mr.end之间的内存区域
while (blk_start_addr < region_end_addr) {
const size_t size = block_size(blk_start_addr);
if (block_is_obj(blk_start_addr)) {
//如果是对象,do_object_bm返回true表示这个对象的结束地址不应该通过set_previous方法记录
last_was_obj_array = cl->do_object_bm(oop(blk_start_addr), derived_mr);
} else {
last_was_obj_array = false;
}
blk_start_addr += size;
}
if (!last_was_obj_array) {
//如果最后一个内存块不是对象,或者是对象但是do_object_bm方法返回false,则记录blk_start_addr
assert((bottom() <= blk_start_addr) && (blk_start_addr <= end()),
"Should be within (closed) used space");
assert(blk_start_addr > prev, "Invariant");
cl->set_previous(blk_start_addr); // min address for next time
}
}
HeapWord*
CompactibleFreeListSpace::object_iterate_careful_m(MemRegion mr,
ObjectClosureCareful* cl) {
assert_lock_strong(freelistLock());
//校验mr在当前Space内
assert(!mr.is_empty() && MemRegion(bottom(),end()).contains(mr),
"mr should be non-empty and within used space");
HeapWord *addr, *end;
size_t size;
//从mr.start对应的内存块的起始地址开始遍历
for (addr = block_start_careful(mr.start()), end = mr.end();
addr < end; addr += size) {
FreeChunk* fc = (FreeChunk*)addr;
if (fc->is_free()) {
//如果是空闲的内存块则跳过
size = fc->size();
} else {
//如果是对象则交给ObjectClosureCareful处理,如果是一个无法解析的对象则返回0,终止处理
size = cl->do_object_careful_m(oop(addr), mr);
if (size == 0) {
return addr;
}
}
}
return NULL;
}
各方法的调用链如下:
”
3、save_marks / promote / oop_since_save_marks_iterate / no_allocs_since_save_marks
这三个方法都是执行promote相关的,所谓promote是指将某个对象从年轻代复制到老年代;save_marks用于保存_saved_mark_word,然后开启promote跟踪,所谓promote跟踪是指记录所有发生了promote的对象,将他们通过链表维护起来;oop_since_save_marks_iterate用于遍历所有发生promote的对象,通过宏定义的,实际有多个方法,如下:
no_allocs_since_save_marks用于判断oop_since_save_marks_iterate遍历是否结束,用于保存被promote的对象的promoInfo中的所有对象是否遍历完成,其实现如下:
void CompactibleFreeListSpace::save_marks() {
assert(Thread::current()->is_VM_thread(),
"Global variable should only be set when single-threaded");
//保留_saved_mark_word
set_saved_mark_word(unallocated_block());
//校验未开始promote
assert(_promoInfo.noPromotions(), "_promoInfo inconsistency");
//准备执行跟踪promote,所谓promote是指将某个对象从新生代拷贝复制到老年代
_promoInfo.startTrackingPromotions();
}
HeapWord* unallocated_block() const {
//BlockOffsetArrayUseUnallocatedBlock表示是否维护unallocated_block,默认为false
if (BlockOffsetArrayUseUnallocatedBlock) {
HeapWord* ub = _bt.unallocated_block();
assert(ub >= bottom() &&
ub <= end(), "space invariant");
return ub;
} else {
return end();
}
}
void set_saved_mark_word(HeapWord* p) { _saved_mark_word = p; }
void PromotionInfo::startTrackingPromotions() {
assert(_spoolHead == _spoolTail && _firstIndex == _nextIndex,
"spooling inconsistency?");
_firstIndex = _nextIndex = 1;
_tracking = true;
}
bool noPromotions() const {
assert(_promoHead != NULL || _promoTail == NULL, "list inconsistency");
return _promoHead == NULL;
}
oop CompactibleFreeListSpace::promote(oop obj, size_t obj_size) {
assert(obj_size == (size_t)obj->size(), "bad obj_size passed in");
assert_locked();
//如果开启了track但是没有足够的空间则返回NULL
if (_promoInfo.tracking() && !_promoInfo.ensure_spooling_space()) {
return NULL;
}
//首先将obj_size做内存对齐,然后从当前空间内分配一块内存
HeapWord* res = allocate(adjustObjectSize(obj_size));
if (res != NULL) {
//分配成功,将原来的对象拷贝到res
Copy::aligned_disjoint_words((HeapWord*)obj, res, obj_size);
//如果开启跟踪
if (_promoInfo.tracking()) {
//记录这个被promoted的对象
_promoInfo.track((PromotedObject*)res);
}
}
return oop(res);
}
#define CFLS_OOP_SINCE_SAVE_MARKS_DEFN(OopClosureType, nv_suffix) \
\
void CompactibleFreeListSpace:: \
oop_since_save_marks_iterate##nv_suffix(OopClosureType* blk) { \
assert(SharedHeap::heap()->n_par_threads() == 0, \
"Shouldn't be called (yet) during parallel part of gc."); \
//实际调用_promoInfo的遍历方法
_promoInfo.promoted_oops_iterate##nv_suffix(blk); \
/* \
遍历的时候会不断从_promoInfo内部的链表中移除元素,遍历结束链表头被置空,noPromotions方法返回true
*/ \
assert(_promoInfo.noPromotions(), "_promoInfo inconsistency"); \
}
ALL_SINCE_SAVE_MARKS_CLOSURES(CFLS_OOP_SINCE_SAVE_MARKS_DEFN)
bool CompactibleFreeListSpace::no_allocs_since_save_marks() {
assert(_promoInfo.tracking(), "No preceding save_marks?");
assert(SharedHeap::heap()->n_par_threads() == 0,
"Shouldn't be called if using parallel gc.");
//promoinfo中的对象都遍历完了
return _promoInfo.noPromotions();
}
各方法的调用链如下:
4、forward / prepare_for_compaction / adjust_pointers / compact / reset_after_compaction
这几个方法都是跟Space压缩相关的,改写了父类的实现,改写如下:
//修改父类实现,不再调用initialize_threshold方法,原有的cross_threshold的用途也被变更成更新bt,
//从而记录被复制对象的起始地址
HeapWord* CompactibleFreeListSpace::forward(oop q, size_t size,
CompactPoint* cp, HeapWord* compact_top) {
assert(this == cp->space, "'this' should be current compaction space.");
//计算可用于compaction的最大空间
size_t compaction_max_size = pointer_delta(end(), compact_top);
assert(adjustObjectSize(size) == cp->space->adjust_object_size_v(size),
"virtual adjustObjectSize_v() method is not correct");
//计算内存对齐后的对象大小
size_t adjusted_size = adjustObjectSize(size);
assert(compaction_max_size >= MinChunkSize || compaction_max_size == 0,
"no small fragments allowed");
assert(minimum_free_block_size() == MinChunkSize,
"for de-virtualized reference below");
//如果剩余可用于compaction的空间不足了
if (adjusted_size + MinChunkSize > compaction_max_size &&
adjusted_size != compaction_max_size) {
do {
//保存compact_top
cp->space->set_compaction_top(compact_top);
//切换到下一个Space
cp->space = cp->space->next_compaction_space();
if (cp->space == NULL) {
//切换到下一个Genaration
cp->gen = GenCollectedHeap::heap()->prev_gen(cp->gen);
assert(cp->gen != NULL, "compaction must succeed");
cp->space = cp->gen->first_compaction_space();
assert(cp->space != NULL, "generation must have a first compaction space");
}
//设置新的Space的compact_top
compact_top = cp->space->bottom();
cp->space->set_compaction_top(compact_top);
//计算设置新的Space的adjusted_size和compaction_max_size
adjusted_size = cp->space->adjust_object_size_v(size);
compaction_max_size = pointer_delta(cp->space->end(), compact_top);
assert(cp->space->minimum_free_block_size() == 0, "just checking");
} while (adjusted_size > compaction_max_size);
}
if ((HeapWord*)q != compact_top) {
//将需要移动的目的地址记录到q的对象头中
q->forward_to(oop(compact_top));
assert(q->is_gc_marked(), "encoding the pointer should preserve the mark");
} else {
// q刚好等于compact_top,则该对象不需要移动了
q->init_mark();
assert(q->forwardee() == NULL, "should be forwarded to NULL");
}
compact_top += adjusted_size;
//通过cross_threshold方法记录被复制对象的起始地址
cp->threshold =
cp->space->cross_threshold(compact_top - adjusted_size, compact_top);
return compact_top;
}
HeapWord* CompactibleFreeListSpace::cross_threshold(HeapWord* start, HeapWord* the_end) {
_bt.single_block(start, the_end);
return end();
}
virtual size_t minimum_free_block_size() const { return MinChunkSize; }
void CompactibleFreeListSpace::prepare_for_compaction(CompactPoint* cp) {
//跟父类相比,就传入方法的block_is_obj和block_size是当前子类的实现
SCAN_AND_FORWARD(cp,end,block_is_obj,block_size);
}
#define obj_size(q) adjustObjectSize(oop(q)->size())
#define adjust_obj_size(s) adjustObjectSize(s)
void CompactibleFreeListSpace::adjust_pointers() {
//adjust_obj_size使用当前子类的实现
SCAN_AND_ADJUST_POINTERS(adjust_obj_size);
}
void CompactibleFreeListSpace::compact() {
//obj_size使用当前子类的实现
SCAN_AND_COMPACT(obj_size);
}
void CompactibleFreeListSpace::reset_after_compaction() {
MemRegion mr(compaction_top(), end());
reset(mr);
//_adaptive_freelists默认为true,则重新填充LinearAllocBlock
if (_adaptive_freelists) {
refillLinearAllocBlocksIfNeeded();
} else {
FreeChunk* fc = dictionary()->find_largest_dict();
if (fc != NULL) {
assert(fc->size() == mr.word_size(),
"Why was the chunk broken up?");
removeChunkFromDictionary(fc);
HeapWord* addr = (HeapWord*) fc;
_smallLinearAllocBlock.set(addr, fc->size() ,
1024*SmallForLinearAlloc, fc->size());
// Note that _unallocated_block is not updated here.
}
}
}
void CompactibleFreeListSpace::reset(MemRegion mr) {
//重置FreeList和dictionary
resetIndexedFreeListArray();
dictionary()->reset();
//BlockOffsetArrayUseUnallocatedBlock表示是否维护bt的unallocated_block属性
if (BlockOffsetArrayUseUnallocatedBlock) {
assert(end() == mr.end(), "We are compacting to the bottom of CMS gen");
_bt.set_unallocated_block(end());
}
if (!mr.is_empty()) {
assert(mr.word_size() >= MinChunkSize, "Chunk size is too small");
//将剩余空间作为一个空闲内存块归还到Dictionary或者FreeList中
_bt.single_block(mr.start(), mr.word_size());
FreeChunk* fc = (FreeChunk*) mr.start();
fc->set_size(mr.word_size());
if (mr.word_size() >= IndexSetSize ) {
returnChunkToDictionary(fc);
} else {
_bt.verify_not_unallocated((HeapWord*)fc, fc->size());
_indexedFreeList[mr.word_size()].return_chunk_at_head(fc);
}
//更新coal_birth计数器
coalBirth(mr.word_size());
}
//_promoInfo和_smallLinearAllocBlock各属性置为NULL
_promoInfo.reset();
_smallLinearAllocBlock._ptr = NULL;
_smallLinearAllocBlock._word_size = 0;
}
void CompactibleFreeListSpace::resetIndexedFreeListArray() {
for (size_t i = 1; i < IndexSetSize; i++) {
assert(_indexedFreeList[i].size() == (size_t) i,
"Indexed free list sizes are incorrect");
_indexedFreeList[i].reset(IndexSetSize);
assert(_indexedFreeList[i].count() == 0, "reset check failed");
assert(_indexedFreeList[i].head() == NULL, "reset check failed");
assert(_indexedFreeList[i].tail() == NULL, "reset check failed");
assert(_indexedFreeList[i].hint() == IndexSetSize, "reset check failed");
}
}
5、beginSweepFLCensus / endSweepFLCensus
这两方法用于在执行Sweep清理前后保存或者重置相关计数器,涉及到的计数器如下:
- ssize_t _desired; //用来计算_demand_rate_estimate
- ssize_t _coal_desired; // 用来控制内存块合并
- ssize_t _bfr_surp; // 清理开始前的当前surplus
- ssize_t _prev_sweep; // 上一次清理结束后的FreeList保存的FreeChunk的个数
- ssize_t _before_sweep; // 清理开始前的FreeList保存的FreeChunk的个数
其调用链如下:
其代码实现如下:
void CompactibleFreeListSpace::beginSweepFLCensus(
float inter_sweep_current,
float inter_sweep_estimate,
float intra_sweep_estimate) {
assert_locked();
size_t i;
for (i = IndexSetStart; i < IndexSetSize; i += IndexSetStride) {
AdaptiveFreeList<FreeChunk>* fl = &_indexedFreeList[i];
if (PrintFLSStatistics > 1) {
gclog_or_tty->print("size[" SIZE_FORMAT "] : ", i);
}
//这4个底层都是调用AllocationStats的方法
fl->compute_desired(inter_sweep_current, inter_sweep_estimate, intra_sweep_estimate);
//CMSSmallCoalSurplusPercent的默认值是1.05,计算一个阈值,控制小块内存被合并成大块内存
fl->set_coal_desired((ssize_t)((double)fl->desired() * CMSSmallCoalSurplusPercent));
fl->set_before_sweep(fl->count());
fl->set_bfr_surp(fl->surplus());
}
//底层调用同上
_dictionary->begin_sweep_dict_census(CMSLargeCoalSurplusPercent,
inter_sweep_current,
inter_sweep_estimate,
intra_sweep_estimate);
}
void CompactibleFreeListSpace::endSweepFLCensus(size_t sweep_count) {
if (PrintFLSStatistics > 0) {
HeapWord* largestAddr = (HeapWord*) dictionary()->find_largest_dict();
gclog_or_tty->print_cr("CMS: Large block " PTR_FORMAT,
p2i(largestAddr));
}
setFLSurplus();
setFLHints();
if (PrintGC && PrintFLSCensus > 0) {
printFLCensus(sweep_count);
}
clearFLCensus();
assert_locked();
//CMSLargeSplitSurplusPercent是一个因子,默认值是1.0,用来控制大的内存块被切分成更小的内存块
//end_sweep_dict_census执行的动作跟对FreeList执行的清理动作是一致的
_dictionary->end_sweep_dict_census(CMSLargeSplitSurplusPercent);
}
void CompactibleFreeListSpace::setFLSurplus() {
assert_locked();
size_t i;
for (i = IndexSetStart; i < IndexSetSize; i += IndexSetStride) {
AdaptiveFreeList<FreeChunk> *fl = &_indexedFreeList[i];
//重新设置surplus
fl->set_surplus(fl->count() -
(ssize_t)((double)fl->desired() * CMSSmallSplitSurplusPercent));
}
}
void CompactibleFreeListSpace::setFLHints() {
assert_locked();
size_t i;
size_t h = IndexSetSize;
//从高到底遍历
for (i = IndexSetSize - 1; i != 0; i -= IndexSetStride) {
AdaptiveFreeList<FreeChunk> *fl = &_indexedFreeList[i];
//设置hint
fl->set_hint(h);
if (fl->surplus() > 0) {
h = i;
}
}
}
void CompactibleFreeListSpace::clearFLCensus() {
assert_locked();
size_t i;
for (i = IndexSetStart; i < IndexSetSize; i += IndexSetStride) {
AdaptiveFreeList<FreeChunk> *fl = &_indexedFreeList[i];
//保存count,计数器清0
fl->set_prev_sweep(fl->count());
fl->set_coal_births(0);
fl->set_coal_deaths(0);
fl->set_split_births(0);
fl->set_split_deaths(0);
}
}
template <class Chunk_t, class FreeList_t>
void BinaryTreeDictionary<Chunk_t, FreeList_t>::end_sweep_dict_census(double splitSurplusPercent) {
// Does walking the tree 3 times hurt?
set_tree_surplus(splitSurplusPercent);
set_tree_hints();
if (PrintGC && Verbose) {
report_statistics();
}
clear_tree_census();
}
6、new_dcto_cl
该方法用于返回一个处理脏的卡表项对应的内存区域的遍历器,用于遍历老年代中引用关系发生变更的内存区域,其调用链如下:
其中CardTableRS::younger_refs_in_space_iterate的实现可以参考《Hotspot 垃圾回收之BarrierSet(三) 源码解析》。 其实现如下:
DirtyCardToOopClosure*
CompactibleFreeListSpace::new_dcto_cl(ExtendedOopClosure* cl,
CardTableModRefBS::PrecisionStyle precision,
HeapWord* boundary) {
return new FreeListSpace_DCTOC(this, _collector, cl, precision, boundary);
}
FreeListSpace_DCTOC并没有直接定义do_MemRegion方法,该方法是父类DirtyCardToOopClosure定义的,其类继承关系如下:
下面来逐一介绍给子类的实现。
7、DirtyCardToOopClosure
DirtyCardToOopClosure的定义在同目录下的space.hpp中,用来遍历脏的卡表对应的内存区域中的对象,注意遍历对象的引用类型属性时,只遍历同样在脏的内存区域中的对象,其实现如下:
DirtyCardToOopClosure(Space* sp, ExtendedOopClosure* cl,
CardTableModRefBS::PrecisionStyle precision,
HeapWord* boundary) :
_sp(sp), _cl(cl), _precision(precision), _boundary(boundary),
_min_done(NULL) {
}
void DirtyCardToOopClosure::do_MemRegion(MemRegion mr) {
//preconsumptionDirtyCardClosure 在CMS 老年代GC前设置,GC后重置为NULL
MemRegionClosure* pCl = _sp->preconsumptionDirtyCardClosure();
if (pCl != NULL) {
pCl->do_MemRegion(mr);
}
HeapWord* bottom = mr.start();
HeapWord* last = mr.last();
HeapWord* top = mr.end();
HeapWord* bottom_obj;
HeapWord* top_obj;
//PrecisionStyle只有这两个枚举值
assert(_precision == CardTableModRefBS::ObjHeadPreciseArray ||
_precision == CardTableModRefBS::Precise,
"Only ones we deal with for now.");
assert(_precision != CardTableModRefBS::ObjHeadPreciseArray ||
_cl->idempotent() || _last_bottom == NULL ||
top <= _last_bottom,
"Not decreasing");
//获取包含bottom的对象地址
bottom_obj = _sp->block_start(bottom);
//获取包含last的对象地址
top_obj = _sp->block_start(last);
assert(bottom_obj <= bottom, "just checking");
assert(top_obj <= top, "just checking");
//根据top_obj来调整top
top = get_actual_top(top, top_obj);
//_min_done适用于并行遍历脏卡表项,用来记录其他线程已经处理过的区域
if (_precision == CardTableModRefBS::ObjHeadPreciseArray &&
_min_done != NULL &&
_min_done < top) {
top = _min_done;
}
bottom = MIN2(bottom, top);
MemRegion extended_mr = MemRegion(bottom, top);
assert(bottom <= top &&
(_precision != CardTableModRefBS::ObjHeadPreciseArray ||
_min_done == NULL ||
top <= _min_done),
"overlap!");
if (!extended_mr.is_empty()) {
//如果extended_mr非空,注意extended_mr的start地址是bottom,要大于bottom_obj
walk_mem_region(extended_mr, bottom_obj, top);
}
//idempotent在父类中默认是false
if (!_cl->idempotent()) {
_min_done = bottom;
} else {
assert(_min_done == _last_explicit_min_done,
"Don't update _min_done for idempotent cl");
}
}
//根据top_obj来调整top
HeapWord* DirtyCardToOopClosure::get_actual_top(HeapWord* top,
HeapWord* top_obj) {
if (top_obj != NULL) {
if (_sp->block_is_obj(top_obj)) {
//如果top_obj是一个对象
if (_precision == CardTableModRefBS::ObjHeadPreciseArray) {
if (oop(top_obj)->is_objArray() || oop(top_obj)->is_typeArray()) {
//如果top_obj是一个数组,因为修改数组元素时只会将被修改数组元素地址对应的卡表项设置为脏的,即不需要遍历整个数组
//此时不需要调整top地址
} else {
//如果top_obj是一个对象,实际将top地址变大了
top = top_obj + oop(top_obj)->size();
}
}
} else {
//如果top_obj是一个空闲内存块
top = top_obj;
}
} else {
assert(top == _sp->end(), "only case where top_obj == NULL");
}
return top;
}
//传入此方法的bottom或者top都是一个对象或者内存块的起始地址
void DirtyCardToOopClosure::walk_mem_region(MemRegion mr,
HeapWord* bottom,
HeapWord* top) {
for (; bottom < top; bottom += _sp->block_size(bottom)) {
//如果bottom是一个对象且位于上一次_saved_mark_word之前
if (_sp->block_is_obj(bottom) &&
!_sp->obj_allocated_since_save_marks(oop(bottom))) {
//遍历oop的其他的同样在mr内的引用类型属性
oop(bottom)->oop_iterate(_cl, mr);
}
}
}
virtual bool obj_allocated_since_save_marks(const oop obj) const {
return (HeapWord*)obj >= saved_mark_word();
}
Space的_preconsumptionDirtyCardClosure属性的调用链如下,gc_prologue_work在老年代GC状态处于Marking和Sweeping时会将_preconsumptionDirtyCardClosure属性置为ModUnionClosure,该类会将指定的内存区域在BitMap中打标,gc_epilogue_work会将该属性顺利置为NULL。
_min_done属性的调用链如下,从调用链可知该属性主要是并行遍历脏的卡表项时使用的。
8、Filtering_DCTOC
Filtering_DCTOC继承自DirtyCardToOopClosure,改写了父类的walk_mem_region方法,注意遍历指定区域内的对象时,要求对象的地址必须小于OopsInGenClosure的_gen_boundary属性,该属性在set_generation方法中完成初始化,其调用链如下:
该类实现如下:
Filtering_DCTOC(Space* sp, ExtendedOopClosure* cl,
CardTableModRefBS::PrecisionStyle precision,
HeapWord* boundary) :
DirtyCardToOopClosure(sp, cl, precision, boundary) {}
void Filtering_DCTOC::walk_mem_region(MemRegion mr,
HeapWord* bottom,
HeapWord* top) {
// Note that this assumption won't hold if we have a concurrent
// collector in this space, which may have freed up objects after
// they were dirtied and before the stop-the-world GC that is
// examining cards here.
assert(bottom < top, "ought to be at least one obj on a dirty card.");
//_boundary实际是OopsInGenClosure的_gen_boundary属性,即该generation的开始地址
//该属性在set_generation方法中完成初始化
if (_boundary != NULL) {
//FilteringClosure是对cl的包装,只处理地址小于_boundary的对象
FilteringClosure filter(_boundary, _cl);
//walk_mem_region_with_cl由子类实现,未提供默认实现
walk_mem_region_with_cl(mr, bottom, top, &filter);
} else {
// No boundary, simply walk the heap with the oop closure.
walk_mem_region_with_cl(mr, bottom, top, _cl);
}
}
inline void OopsInGenClosure::set_generation(Generation* gen) {
_gen = gen;
_gen_boundary = _gen->reserved().start();
// Barrier set for the heap, must be set after heap is initialized
if (_rs == NULL) {
GenRemSet* rs = SharedHeap::heap()->rem_set();
assert(rs->rs_kind() == GenRemSet::CardTable, "Wrong rem set kind");
_rs = (CardTableRS*)rs;
}
}
FilteringClosure(HeapWord* boundary, ExtendedOopClosure* cl) :
ExtendedOopClosure(cl->_ref_processor), _boundary(boundary),
_cl(cl) {}
//do_oop和do_oop_nv转换成对此方法的调用
template <class T> inline void do_oop_work(T* p) {
T heap_oop = oopDesc::load_heap_oop(p);
if (!oopDesc::is_null(heap_oop)) {
oop obj = oopDesc::decode_heap_oop_not_null(heap_oop);
//就多了一道地址的过滤,注意此处是小于
if ((HeapWord*)obj < _boundary) {
//由cl处理该对象
_cl->do_oop(p);
}
}
}
9、 FreeListSpace_DCTOC
FreeListSpace_DCTOC继承自Filtering_DCTOC,实现了父类的walk_mem_region_with_cl方法,该方法有两个版本,通过宏定义实现,每个方法都有并行处理和单线程处理两个版本,我们重点关注后者。FreeListSpace_DCTOC在遍历对象时增加了两个条件,一是要求对象不是promoted对象,即被复制到to区或者老年代的对象,二是要求对象是存活对象。其实现如下:
FreeListSpace_DCTOC(CompactibleFreeListSpace* sp,
CMSCollector* collector,
ExtendedOopClosure* cl,
CardTableModRefBS::PrecisionStyle precision,
HeapWord* boundary) :
Filtering_DCTOC(sp, cl, precision, boundary),
_cfls(sp), _collector(collector) {}
//其实现是通过宏定义完成的
FreeListSpace_DCTOC__walk_mem_region_with_cl_DEFN(ExtendedOopClosure)
FreeListSpace_DCTOC__walk_mem_region_with_cl_DEFN(FilteringClosure)
#define FreeListSpace_DCTOC__walk_mem_region_with_cl_DEFN(ClosureType) \
void FreeListSpace_DCTOC::walk_mem_region_with_cl(MemRegion mr, \
HeapWord* bottom, \
HeapWord* top, \
ClosureType* cl) { \
bool is_par = SharedHeap::heap()->n_par_threads() > 0; \
if (is_par) { \
assert(SharedHeap::heap()->n_par_threads() == \
SharedHeap::heap()->workers()->active_workers(), "Mismatch"); \
//并行处理的版本
walk_mem_region_with_cl_par(mr, bottom, top, cl); \
} else { \
//单线程处理的版本,关注此版本即可
walk_mem_region_with_cl_nopar(mr, bottom, top, cl); \
} \
} \
void FreeListSpace_DCTOC::walk_mem_region_with_cl_par(MemRegion mr, \
HeapWord* bottom, \
HeapWord* top, \
ClosureType* cl) { \
/* Skip parts that are before "mr", in case "block_start" sent us \
back too far. */ \
HeapWord* mr_start = mr.start(); \
size_t bot_size = _cfls->CompactibleFreeListSpace::block_size(bottom); \
HeapWord* next = bottom + bot_size; \
while (next < mr_start) { \
bottom = next; \
bot_size = _cfls->CompactibleFreeListSpace::block_size(bottom); \
next = bottom + bot_size; \
} \
\
while (bottom < top) { \
if (_cfls->CompactibleFreeListSpace::block_is_obj(bottom) && \
!_cfls->CompactibleFreeListSpace::obj_allocated_since_save_marks( \
oop(bottom)) && \
!_collector->CMSCollector::is_dead_obj(oop(bottom))) { \
size_t word_sz = oop(bottom)->oop_iterate(cl, mr); \
bottom += _cfls->adjustObjectSize(word_sz); \
} else { \
bottom += _cfls->CompactibleFreeListSpace::block_size(bottom); \
} \
} \
} \
void FreeListSpace_DCTOC::walk_mem_region_with_cl_nopar(MemRegion mr, \
HeapWord* bottom, \
HeapWord* top, \
ClosureType* cl) { \
/* Skip parts that are before "mr", in case "block_start" sent us \
back too far. */ \
HeapWord* mr_start = mr.start(); \
//获取bottom对应内存块的大小
size_t bot_size = _cfls->CompactibleFreeListSpace::block_size_nopar(bottom); \
//下一个内存块的起始地址
HeapWord* next = bottom + bot_size; \
//不断往前遍历,找到大于mr_start的第一个内存块的起始地址,bottom被赋值成该地址
while (next < mr_start) { \
bottom = next; \
bot_size = _cfls->CompactibleFreeListSpace::block_size_nopar(bottom); \
next = bottom + bot_size; \
} \
\
while (bottom < top) { \
if (_cfls->CompactibleFreeListSpace::block_is_obj_nopar(bottom) && \ //该地址是一个对象
!_cfls->CompactibleFreeListSpace::obj_allocated_since_save_marks( \ //该对象不是promoted对象
oop(bottom)) && \
!_collector->CMSCollector::is_dead_obj(oop(bottom))) { \ //该对象是存活对象
//满足上述条件则遍历该对象的引用类型属性,要求被遍历属性同样在mr内
size_t word_sz = oop(bottom)->oop_iterate(cl, mr); \
//计算下一个内存块的起始地址
bottom += _cfls->adjustObjectSize(word_sz); \
} else { \
bottom += _cfls->CompactibleFreeListSpace::block_size_nopar(bottom); \
} \
} \
}
inline bool CMSCollector::is_dead_obj(oop obj) const {
HeapWord* addr = (HeapWord*)obj;
assert((_cmsGen->cmsSpace()->is_in_reserved(addr)
&& _cmsGen->cmsSpace()->block_is_obj(addr)),
"must be object");
return should_unload_classes() &&
_collectorState == Sweeping &&
!_markBitMap.isMarked(addr);
}
bool obj_allocated_since_save_marks(const oop obj) const {
assert(is_in_reserved(obj), "Wrong space?");
return ((PromotedObject*)obj)->hasPromotedMark();
}
其中跟hasPromotedMark对应的setPromotedMark方法的调用链如下: