目录
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
这三个方法都是执行promote相关的,所谓promote是指将某个对象从年轻代复制到老年代;save_marks用于保存_saved_mark_word,然后开启promote跟踪,所谓promote跟踪是指记录所有发生了promote的对象,将他们通过链表维护起来;oop_since_save_marks_iterate用于遍历所有发生promote的对象,通过宏定义的,实际有多个方法,如下:
其实现如下:
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)
各方法的调用链如下:
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();
}