上一篇CMSCollector 之 二重点讲解了checkpointRootsInitial和markFromRoots方法的实现,本篇继续讲解其他方法的实现。
1、Par_MarkFromRootsClosure
Par_MarkFromRootsClosure用来处理cmsSpace的某一段内存区域在BitMap中已打标的bit,即第一遍标记中被标记成存活的对象,是CMSConcMarkingTask::do_scan_and_mark中使用的遍历器,其实现如下:
Par_MarkFromRootsClosure::Par_MarkFromRootsClosure(CMSConcMarkingTask* task,
CMSCollector* collector, MemRegion span,
CMSBitMap* bit_map,
OopTaskQueue* work_queue, //传入的是GC线程对应的work_queue
CMSMarkStack* overflow_stack, //传入的是全局的CMSCollector的_markStack属性
bool should_yield): //should_yield传入的是是否同步GC
_collector(collector),
_whole_span(collector->_span),
_span(span),
_bit_map(bit_map),
_mut(&collector->_modUnionTable),
_work_queue(work_queue),
_overflow_stack(overflow_stack),
_yield(should_yield),
_skip_bits(0),
_task(task)
{
assert(_work_queue->size() == 0, "work_queue should be empty");
_finger = span.start();
_threshold = _finger; //clear-on-enter优化使用的
assert(_span.contains(_finger), "Out of bounds _finger?");
}
//注意只有打标的bit才会调用此方法
bool Par_MarkFromRootsClosure::do_bit(size_t offset) {
if (_skip_bits > 0) {
//如果_skip_bits大于0则跳过当前位
_skip_bits--;
return true;
}
//获取该偏移量对应的地址
HeapWord* addr = _bit_map->startWord() + offset;
assert(_bit_map->endWord() && addr < _bit_map->endWord(),
"address out of range");
assert(_bit_map->isMarked(addr), "tautology");
if (_bit_map->isMarked(addr+1)) {
//addr+1也被标记了,说明这是一个未初始化的对象
assert(_skip_bits == 0, "tautology");
_skip_bits = 2; //addr+1和addr+size都被打标了,这两个需要跳过,不做处理
oop p = oop(addr);
if (p->klass_or_null() == NULL) {
// klass为null,进一步证实其未初始化,不需要遍历,返回true
return true;
}
}
scan_oops_in_oop(addr);
return true;
}
void Par_MarkFromRootsClosure::scan_oops_in_oop(HeapWord* ptr) {
assert(_bit_map->isMarked(ptr), "expected bit to be set");
//校验_work_queue是空的
assert(_work_queue->size() == 0,
"should drain stack to limit stack usage");
oop obj = oop(ptr);
assert(obj->is_oop(true), "should be an oop");
assert(_finger <= ptr, "_finger runneth ahead");
//修改_finger属性,指向obj的end地址
_finger = ptr + obj->size();
assert(_finger > ptr, "we just incremented it above");
//CMSCleanOnEnter默认为true,表示是否采用这项优化来减少脏的卡片的数量
if (CMSCleanOnEnter && (_finger > _threshold)) {
HeapWord* old_threshold = _threshold;
//校验old_threshold是按照card_size对齐的
assert(old_threshold == (HeapWord*)round_to(
(intptr_t)old_threshold, CardTableModRefBS::card_size),
"_threshold should always be card-aligned");
//将_finger按照card_size对齐的,计算新的_threshold
_threshold = (HeapWord*)round_to(
(intptr_t)_finger, CardTableModRefBS::card_size);
MemRegion mr(old_threshold, _threshold);
assert(!mr.is_empty(), "Control point invariant");
assert(_span.contains(mr), "Should clear within span"); // _whole_span ??
//清空mut中mr对应的区域
_mut->clear_range(mr);
}
//获取_global_finger的地址
HeapWord** gfa = _task->global_finger_addr();
Par_PushOrMarkClosure pushOrMarkClosure(_collector,
_span, _bit_map,
_work_queue,
_overflow_stack,
_finger,
gfa, this);
//将obj方法_work_queue中
bool res = _work_queue->push(obj); // overflow could occur here
assert(res, "Will hold once we use workqueues");
while (true) {
oop new_oop;
//第一次遍历时就是处理上面push进的obj
if (!_work_queue->pop_local(new_oop)) {
//_work_queue是空的,从_overflow_stack获取待处理的oop放入_work_queue中
if (CMSConcMarkingTask::get_work_from_overflow_stack(
_overflow_stack, _work_queue)) {
//_overflow_stack中获取成功,则检查是否需要yield,如果需要则执行yield
do_yield_check();
continue;
} else {
_overflow_stack中获取失败,则终止循环
break;
}
}
assert(new_oop->is_oop(true), "Oops! expected to pop an oop");
//遍历该oop所引用的其他oop,会把这些引用的oop打标然后再放入到_work_queue或者_overflow_stack中,从而遍历他们所引用的oop,如此循环直到所有引用的oop都遍历完成
new_oop->oop_iterate(&pushOrMarkClosure);
//处理掉一个oop,检查是否需要yield
do_yield_check();
}
assert(_work_queue->size() == 0, "tautology, emphasizing post-condition");
}
HeapWord** global_finger_addr() { return &_global_finger; }
inline void Par_MarkFromRootsClosure::do_yield_check() {
//同步GC下_yield为false,即同步GC下不可能出现yield
//只有异步GC,_yield为true,即CMSThread执行的GC才需要yield,且必须是要求CMSThread yield,而不是前台GC被激活了
if (ConcurrentMarkSweepThread::should_yield() &&
!_collector->foregroundGCIsActive() &&
_yield) {
do_yield_work();
}
}
void Par_MarkFromRootsClosure::do_yield_work() {
assert(_task != NULL, "sanity");
_task->yield();
}
2、Par_PushOrMarkClosure
Par_PushOrMarkClosure是Par_MarkFromRootsClosure中用来遍历已标记oop所引用的其他oop的,其实现如下:
Par_PushOrMarkClosure::Par_PushOrMarkClosure(CMSCollector* collector,
MemRegion span,
CMSBitMap* bit_map,
OopTaskQueue* work_queue,
CMSMarkStack* overflow_stack,
HeapWord* finger,
HeapWord** global_finger_addr,
Par_MarkFromRootsClosure* parent) :
MetadataAwareOopClosure(collector->ref_processor()),
_collector(collector),
_whole_span(collector->_span),
_span(span),
_bit_map(bit_map),
_work_queue(work_queue),
_overflow_stack(overflow_stack),
_finger(finger),
_global_finger_addr(global_finger_addr),
_parent(parent)
{ }
void Par_PushOrMarkClosure::do_oop(oop* p) { Par_PushOrMarkClosure::do_oop_work(p); }
void Par_PushOrMarkClosure::do_oop(narrowOop* p) { Par_PushOrMarkClosure::do_oop_work(p); }
inline void do_oop_nv(oop* p) { Par_PushOrMarkClosure::do_oop_work(p); }
inline void do_oop_nv(narrowOop* p) { Par_PushOrMarkClosure::do_oop_work(p); }
void Par_PushOrMarkClosure::do_oop(oop obj) {
// Ignore mark word because we are running concurrent with mutators.
assert(obj->is_oop_or_null(true), "expected an oop or NULL");
HeapWord* addr = (HeapWord*)obj;
//如果addr地址在老年代中,并且未被标记
if (_whole_span.contains(addr) && !_bit_map->isMarked(addr)) {
//将该oop打标,res返回false表示其他线程已经完成打标了
bool res = _bit_map->par_mark(addr); // now grey
volatile HeapWord** gfa = (volatile HeapWord**)_global_finger_addr;
//下列三种情况都不做任何处理
if ( !res //其他线程完成打标了,他们会负责打标后的处理
|| (addr >= *gfa) //addr大于global_finger的值,后面的任务会处理该oop
|| (_span.contains(addr) && addr >= _finger)) { //该对象位于当前遍历的内存块内,后面会遍历处理的
return;
}
// the bit map iteration has already either passed, or
// sampled, this bit in the bit map; we'll need to
// use the marking stack to scan this oop's oops.
bool simulate_overflow = false;
if (simulate_overflow ||
//将obj先尝试加入到_work_queue中,如果满了返回false,则尝试加入到_overflow_stack中
//如果_work_queue和_overflow_stack都满了,则返回false,有一个成功则返回true
//加入到_work_queue和_overflow_stack中的目的是为了继续遍历该oop引用的其他oop
!(_work_queue->push(obj) || _overflow_stack->par_push(obj))) {
//_work_queue和_overflow_stack都满了
if (PrintCMSStatistics != 0) {
gclog_or_tty->print_cr("CMS marking stack overflow (benign) at "
SIZE_FORMAT, _overflow_stack->capacity());
}
assert(simulate_overflow ||
_work_queue->size() == _work_queue->max_elems(),
"Else push should have succeeded");
//处理stack_overflow满了的问题,取stack_overflow中的最小地址作为_restart_addr,然后清空
//stack_overflow中的数据并扩容,注意此时并不会执行yeild,扩容后继续遍历,等待遍历结束会重新从restart_addr处开始遍历
handle_stack_overflow(addr);
}
//检查是否需要yield,如果需要则yield
do_yield_check();
}
}
void Par_PushOrMarkClosure::handle_stack_overflow(HeapWord* lost) {
//获取_overflow_stack的锁
MutexLockerEx ml(_overflow_stack->par_lock(),
Mutex::_no_safepoint_check_flag);
//取_overflow_stack中地址最小的一个元素
HeapWord* ra = (HeapWord*)_overflow_stack->least_value(lost);
//设置_restart_addr,方便后面重新扫描
_collector->lower_restart_addr(ra);
//丢掉_overflow_stack中的内容,然后扩容
_overflow_stack->reset(); // discard stack contents
_overflow_stack->expand(); // expand the stack if possible
}
void CMSCollector::lower_restart_addr(HeapWord* low) {
//重置_restart_addr
assert(_span.contains(low), "Out of bounds addr");
if (_restart_addr == NULL) {
_restart_addr = low;
} else {
_restart_addr = MIN2(_restart_addr, low);
}
}
inline void Par_PushOrMarkClosure::do_yield_check() {
_parent->do_yield_check();
}
3、Par_ConcMarkingClosure
Par_ConcMarkingClosure是CMSConcMarkingTask::do_work_steal中使用的遍历器,其实现跟Par_PushOrMarkClosure基本一致,就是多了一个遍历_work_queue的方法,其实现如下:
Par_ConcMarkingClosure(CMSCollector* collector, CMSConcMarkingTask* task, OopTaskQueue* work_queue,
CMSBitMap* bit_map, CMSMarkStack* overflow_stack):
MetadataAwareOopClosure(collector->ref_processor()),
_collector(collector),
_task(task),
_span(collector->_span),
_work_queue(work_queue),
_bit_map(bit_map),
_overflow_stack(overflow_stack)
{ }
//通过DO_OOP_WORK_DEFN转换成对do_oop的调用
void Par_ConcMarkingClosure::do_oop(oop* p) { Par_ConcMarkingClosure::do_oop_work(p); }
void Par_ConcMarkingClosure::do_oop(narrowOop* p) { Par_ConcMarkingClosure::do_oop_work(p); }
void Par_ConcMarkingClosure::trim_queue(size_t max) {
while (_work_queue->size() > max) {
oop new_oop;
//从_work_queue中pop出一个oop
if (_work_queue->pop_local(new_oop)) {
//校验该oop是oop,被打标了,且位于span内
assert(new_oop->is_oop(), "Should be an oop");
assert(_bit_map->isMarked((HeapWord*)new_oop), "Grey object");
assert(_span.contains((HeapWord*)new_oop), "Not in span");
//遍历该oop引用的其他oop
new_oop->oop_iterate(this); // do_oop() above
//检查是否需要yeild,如果需要则yield
do_yield_check();
}
}
}
void do_yield_check() {
if (_task->should_yield()) {
_task->yield();
}
}
void Par_ConcMarkingClosure::do_oop(oop obj) {
assert(obj->is_oop_or_null(true), "expected an oop or NULL");
HeapWord* addr = (HeapWord*)obj;
//处理逻辑和Par_PushOrMarkClosure基本一致
if (_span.contains(addr) && !_bit_map->isMarked(addr)) {
if (_bit_map->par_mark(addr)) { // ... now grey
// push on work queue (grey set)
bool simulate_overflow = false;
if (simulate_overflow ||
!(_work_queue->push(obj) || _overflow_stack->par_push(obj))) {
// stack overflow
if (PrintCMSStatistics != 0) {
gclog_or_tty->print_cr("CMS marking stack overflow (benign) at "
SIZE_FORMAT, _overflow_stack->capacity());
assert(simulate_overflow ||
_work_queue->size() == _work_queue->max_elems(),
"Else push should have succeeded");
handle_stack_overflow(addr);
}
} // Else, some other thread got there first
do_yield_check();
}
}
void Par_ConcMarkingClosure::handle_stack_overflow(HeapWord* lost) {
MutexLockerEx ml(_overflow_stack->par_lock(),
Mutex::_no_safepoint_check_flag);
HeapWord* ra = (HeapWord*)_overflow_stack->least_value(lost);
_collector->lower_restart_addr(ra);
_overflow_stack->reset(); // discard stack contents
_overflow_stack->expand(); // expand the stack if possible
}
4、Marking 总结
Marking不要求JVM处于安全点,Marking遍历的是老年代在BitMap中对应的被打标的Bit(位),这些位就是第一个步骤InitialMarking中遍历某个对象所引用的其他对象时打标的。根据BitMap中的打标的位找到对应的对象地址,然后遍历该对象所引用的其他对象,如果其他对象中有没有在BitMap中打标的,则在BitMap中打标,并将其加入到一个跟单个GC线程绑定的对象栈中,然后以同样的方式遍历处理对象栈中的对象,不断循环直到某个对象没有引用类型属性为止。
5、preclean_mod_union_table / preclean_card_table / preclean_klasses
卡表(CardTableModRefBS)是用一个字节表示一个卡表项,参考《Hotspot 垃圾回收之BarrierSet(一) 源码解析》,_modUnionTable是一个CMSBitMap,用一个位来表示一个卡表项,位打标了表示这个卡表项是脏的。前面两个方法的处理逻辑是高度相似的,如果修改其中一个方法,应该检查另外一个方法是否需要修改。第一个方法会从老年代对应的_modUnionTable中不断循环查找一段连续的脏的位,即发生修改的卡表项,然后遍历这段脏的位对应的内存空间中的对象。第二个方法是直接遍历老年代对应的卡表项,不断循环查找一段连续的脏的卡表项,并将这些卡表项的值重置为preclean_card,然后遍历这些卡表项对应的内存空间中包含的对象。最后一个方法preclean_klasses用来遍历所有加载的klass。这三个方法都是preclean_work的底层实现。
size_t CMSCollector::preclean_mod_union_table(
ConcurrentMarkSweepGeneration* gen,
ScanMarkedObjectsAgainCarefullyClosure* cl) {
verify_work_stacks_empty();
verify_overflow_empty();
//获取老年代的起止地址
HeapWord* startAddr = gen->reserved().start();
HeapWord* endAddr = gen->reserved().end();
cl->setFreelistLock(gen->freelistLock()); // needed for yielding
//numDirtyCards表示一次循环时找到的脏的卡片数量
//cumNumDirtyCards表示整个循环期间累计的总的脏的卡片数量
size_t numDirtyCards, cumNumDirtyCards;
HeapWord *nextAddr, *lastAddr;
for (cumNumDirtyCards = numDirtyCards = 0,
nextAddr = lastAddr = startAddr;
nextAddr < endAddr;
nextAddr = lastAddr, cumNumDirtyCards += numDirtyCards) {
ResourceMark rm;
HandleMark hm;
MemRegion dirtyRegion;
{
stopTimer();
//获取CMS Token
CMSTokenSync ts(true);
startTimer();
sample_eden();
//获取nextAddr之后的一段连续的脏的区域,并将这段区域的标记清除,注意这段区域同样位于老年代的堆内存区域中
dirtyRegion =
_modUnionTable.getAndClearMarkedRegion(nextAddr, endAddr);
assert(dirtyRegion.start() >= nextAddr,
"returned region inconsistent?");
}
//记录上一个dirtyRegion的终止地址,下一次查找时从该地址开始
lastAddr = dirtyRegion.end();
//获取对应的卡表数量
numDirtyCards =
_modUnionTable.heapWordDiffToOffsetDiff(dirtyRegion.word_size());
if (!dirtyRegion.is_empty()) {
assert(numDirtyCards > 0, "consistency check");
HeapWord* stop_point = NULL;
stopTimer();
//获取CMS Token,freelistLock锁和bitMapLock锁
CMSTokenSyncWithLocks ts(true, gen->freelistLock(),
bitMapLock());
startTimer();
{
verify_work_stacks_empty();
verify_overflow_empty();
sample_eden();
//遍历这一段脏的区域
//返回的stop_point如果非空,要么是遍历时发现一个无法解析的对象的地址,要么是处于abortable preclean
//阶段,preclean需要被中止
stop_point =
gen->cmsSpace()->object_iterate_careful_m(dirtyRegion, cl);
}
if (stop_point != NULL) {
assert((_collectorState == AbortablePreclean && should_abort_preclean()),
"Should only be AbortablePreclean.");
//将未遍历的区域重新打标
_modUnionTable.mark_range(MemRegion(stop_point, dirtyRegion.end()));
if (should_abort_preclean()) {
break; //终止preclean
} else {
//计算下一次遍历的起始地址
lastAddr = next_card_start_after_block(stop_point);
}
}
} else {
//dirtyRegion是空的,即遍历完成,没有找到脏的卡表项
assert(lastAddr == endAddr, "consistency check");
assert(numDirtyCards == 0, "consistency check");
break;
}
}
verify_work_stacks_empty();
verify_overflow_empty();
return cumNumDirtyCards;
}
void CMSCollector::sample_eden() {
//
assert(Thread::current()->is_ConcurrentGC_thread(),
"Only the cms thread may collect Eden samples");
assert(ConcurrentMarkSweepThread::cms_thread_has_cms_token(),
"Should collect samples while holding CMS token");
if (!_start_sampling) {
return;
}
//CMSEdenChunksRecordAlways为true,则_eden_chunk_array由年轻代分配内存时使用,该参数默认为true
//所以只有在CMSEdenChunksRecordAlways为false,即年轻代不使用时,才使用,其采样逻辑不变
if (_eden_chunk_array != NULL && !CMSEdenChunksRecordAlways) {
if (_eden_chunk_index < _eden_chunk_capacity) {
_eden_chunk_array[_eden_chunk_index] = *_top_addr; // take sample
assert(_eden_chunk_array[_eden_chunk_index] <= *_end_addr,
"Unexpected state of Eden");
if (_eden_chunk_index == 0 ||
(pointer_delta(_eden_chunk_array[_eden_chunk_index],
_eden_chunk_array[_eden_chunk_index-1])
>= CMSSamplingGrain)) {
_eden_chunk_index++; // commit sample
}
}
}
if ((_collectorState == AbortablePreclean) && !_abort_preclean) {
size_t used = get_eden_used();
size_t capacity = get_eden_capacity();
assert(used <= capacity, "Unexpected state of Eden");
//CMSScheduleRemarkEdenPenetration的默认值是50,即已使用内存超过总容量的50%时,将_abort_preclean置为true
if (used > (capacity/100 * CMSScheduleRemarkEdenPenetration)) {
_abort_preclean = true;
}
}
}
inline size_t CMSBitMap::heapWordDiffToOffsetDiff(size_t diff) const {
assert((diff & ((1 << _shifter) - 1)) == 0, "argument check");
return diff >> _shifter;
}
inline bool CMSCollector::should_abort_preclean() const {
return _collectorState == AbortablePreclean &&
(_abort_preclean || _foregroundGCIsActive ||
GenCollectedHeap::heap()->incremental_collection_will_fail(true /* consult_young */));
}
HeapWord* CMSCollector::next_card_start_after_block(HeapWord* addr) const {
size_t sz = 0;
oop p = (oop)addr;
if (p->klass_or_null() != NULL) {
//p是一个正常的对象地址
sz = CompactibleFreeListSpace::adjustObjectSize(p->size());
} else {
//p是一个未初始化对象的地址,则根据该对象的终止地址确认对象大小
sz = block_size_using_printezis_bits(addr);
}
assert(sz > 0, "size must be nonzero");
//确定下一个遍历的内存块的地址,将该地址按照card_size对齐,获取下一次遍历的起始地址
HeapWord* next_block = addr + sz;
HeapWord* next_card = (HeapWord*)round_to((uintptr_t)next_block,
CardTableModRefBS::card_size);
assert(round_down((uintptr_t)addr, CardTableModRefBS::card_size) <
round_down((uintptr_t)next_card, CardTableModRefBS::card_size),
"must be different cards");
return next_card;
}
size_t CMSCollector::block_size_using_printezis_bits(HeapWord* addr) const {
//校验addr是一个未初始化对象地址,参考CMSCollector::direct_allocated方法
assert(_markBitMap.isMarked(addr) && _markBitMap.isMarked(addr + 1),
"missing Printezis mark?");
//获取下一个打标的位的地址,即该对象的终止地址
HeapWord* nextOneAddr = _markBitMap.getNextMarkedWordAddress(addr + 2);
//计算该对象的大小
size_t size = pointer_delta(nextOneAddr + 1, addr);
//校验该对象的大小符合规范
assert(size == CompactibleFreeListSpace::adjustObjectSize(size),
"alignment problem");
assert(size >= 3, "Necessary for Printezis marks to work");
return size;
}
size_t CMSCollector::preclean_card_table(ConcurrentMarkSweepGeneration* gen,
ScanMarkedObjectsAgainCarefullyClosure* cl) {
//preclean_mod_union_table中是通过gen->reserved()获取起止地址,这个是预先申请的一段连续地址空间,部分空间实际未分配
//通过_virtual_space的high和low获取的地址是当前已分配内存的起止地址,其范围要小于gen->reserved()获取的
HeapWord* endAddr = (HeapWord*)(gen->_virtual_space.high());
HeapWord* startAddr = (HeapWord*)(gen->_virtual_space.low());
cl->setFreelistLock(gen->freelistLock()); // needed for yielding
size_t numDirtyCards, cumNumDirtyCards;
HeapWord *lastAddr, *nextAddr;
for (cumNumDirtyCards = numDirtyCards = 0,
nextAddr = lastAddr = startAddr;
nextAddr < endAddr;
nextAddr = lastAddr, cumNumDirtyCards += numDirtyCards) {
ResourceMark rm;
HandleMark hm;
MemRegion dirtyRegion;
{
stopTimer();
//获取CMS Token
CMSTokenSync x(true); // is cms thread
startTimer();
sample_eden();
//遍历nextAddr, endAddr对应的卡表项,找到一段连续的脏的卡表项,将其重置为precleaned_card
dirtyRegion = _ct->ct_bs()->dirty_card_range_after_reset(
MemRegion(nextAddr, endAddr),
true,
CardTableModRefBS::precleaned_card_val());
assert(dirtyRegion.start() >= nextAddr,
"returned region inconsistent?");
}
lastAddr = dirtyRegion.end();
//获取脏的卡表项的数量
numDirtyCards =
dirtyRegion.word_size()/CardTableModRefBS::card_size_in_words;
if (!dirtyRegion.is_empty()) {
stopTimer();
CMSTokenSyncWithLocks ts(true, gen->freelistLock(), bitMapLock());
startTimer();
sample_eden();
verify_work_stacks_empty();
verify_overflow_empty();
//遍历dirtyRegion中所包含的对象
HeapWord* stop_point =
gen->cmsSpace()->object_iterate_careful_m(dirtyRegion, cl);
if (stop_point != NULL) {
assert((_collectorState == AbortablePreclean && should_abort_preclean()),
"Should only be AbortablePreclean.");
//将剩余的未遍历区域重新标记为脏的
_ct->ct_bs()->invalidate(MemRegion(stop_point, dirtyRegion.end()));
if (should_abort_preclean()) {
break; //终止循环
} else {
//计算下一次开始遍历的起始地址
lastAddr = next_card_start_after_block(stop_point);
}
}
} else {
//dirtyRegion是空的
break;
}
}
verify_work_stacks_empty();
verify_overflow_empty();
return cumNumDirtyCards;
}
void CMSCollector::preclean_klasses(MarkRefsIntoAndScanClosure* cl, Mutex* freelistLock) {
cl->set_freelistLock(freelistLock);
//获取CMS Token,freelistLock,bitMapLock锁
CMSTokenSyncWithLocks ts(true, freelistLock, bitMapLock());
//遍历所有加载的klass
PrecleanKlassClosure preclean_klass_closure(cl);
ClassLoaderDataGraph::classes_do(&preclean_klass_closure);
verify_work_stacks_empty();
verify_overflow_empty();
}
6、preclean / abortable_preclean
这两个方法分别用来执行Precleaning和AbortablePreclean步骤,这两个步骤的核心逻辑都是同一个方法preclean_work,而且两者是相关联的。
void CMSCollector::preclean() {
//校验调用线程是CMS Thread
check_correct_thread_executing();
assert(Thread::current()->is_ConcurrentGC_thread(), "Wrong thread");
//校验_markStack和_overflow_list为空
verify_work_stacks_empty();
verify_overflow_empty();
_abort_preclean = false;
//CMSPrecleaningEnabled表示是否允许并行的预清理,默认为true
if (CMSPrecleaningEnabled) {
//CMSEdenChunksRecordAlways表示是否记录eden区分配的chunk的地址,默认为true
if (!CMSEdenChunksRecordAlways) {
_eden_chunk_index = 0;
}
size_t used = get_eden_used();
size_t capacity = get_eden_capacity();
//CMSScheduleRemarkSamplingRatio的默认值是5,CMSScheduleRemarkEdenPenetration的默认值是50
//即默认情况下used小于capacity的10%的时候_start_sampling为true
if (used < (capacity/(CMSScheduleRemarkSamplingRatio * 100)
* CMSScheduleRemarkEdenPenetration)) {
_start_sampling = true;
} else {
_start_sampling = false;
}
//TraceCPUTime和CMSPhaseAccounting都是记录日志使用
TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty);
CMSPhaseAccounting pa(this, "preclean", _gc_tracer_cm->gc_id(), !PrintGCDetails);
//CMSPrecleanRefLists1表示在预处理环节清理Reference实例,默认为true
//CMSPrecleanSurvivors1表示是否在预处理环节清理survivor区,默认为false
preclean_work(CMSPrecleanRefLists1, CMSPrecleanSurvivors1);
}
CMSTokenSync x(true); // is cms thread
//修改状态
if (CMSPrecleaningEnabled) {
sample_eden();
_collectorState = AbortablePreclean;
} else {
_collectorState = FinalMarking;
}
verify_work_stacks_empty();
verify_overflow_empty();
}
inline size_t CMSCollector::get_eden_used() const {
return _young_gen->as_DefNewGeneration()->eden()->used();
}
inline size_t CMSCollector::get_eden_capacity() const {
return _young_gen->as_DefNewGeneration()->eden()->capacity();
}
size_t CMSCollector::preclean_work(bool clean_refs, bool clean_survivor) {
//校验状态
assert(_collectorState == Precleaning ||
_collectorState == AbortablePreclean, "incorrect state");
ResourceMark rm;
HandleMark hm;
ReferenceProcessor* rp = ref_processor();
//临时设置discovery_is_mt属性为false
ReferenceProcessorMTDiscoveryMutator rp_mut_discovery(rp, false);
if (clean_refs) {
CMSPrecleanRefsYieldClosure yield_cl(this);
assert(rp->span().equals(_span), "Spans should be equal");
CMSKeepAliveClosure keep_alive(this, _span, &_markBitMap,
&_markStack, true /* preclean */);
CMSDrainMarkingStackClosure complete_trace(this,
_span, &_markBitMap, &_markStack,
&keep_alive, true /* preclean */);
stopTimer();
//获取CMS Token 和bitMapLock锁
CMSTokenSyncWithLocks x(true /* is cms thread */,
bitMapLock());
startTimer();
//如果CMSEdenChunksRecordAlways为false则执行eden的top地址采样
sample_eden();
GCTimer *gc_timer = NULL; // Currently not tracing concurrent phases
//Reference实例的预处理
//rp->is_alive_non_header方法返回的是CMSCollector的CMSIsAliveClosure,参考CMSCollector::ref_processor_init方法实现
rp->preclean_discovered_references(
rp->is_alive_non_header(), &keep_alive, &complete_trace, &yield_cl,
gc_timer, _gc_tracer_cm->gc_id());
}
if (clean_survivor) { // preclean the active survivor space(s)
assert(_young_gen->kind() == Generation::DefNew ||
_young_gen->kind() == Generation::ParNew ||
_young_gen->kind() == Generation::ASParNew,
"incorrect type for cast");
DefNewGeneration* dng = (DefNewGeneration*)_young_gen;
PushAndMarkClosure pam_cl(this, _span, ref_processor(),
&_markBitMap, &_modUnionTable,
&_markStack, true /* precleaning phase */);
stopTimer();
CMSTokenSyncWithLocks ts(true /* is cms thread */,
bitMapLock());
startTimer();
unsigned int before_count =
GenCollectedHeap::heap()->total_collections();
SurvivorSpacePrecleanClosure
sss_cl(this, _span, &_markBitMap, &_markStack,
&pam_cl, before_count, CMSYield);
//遍历survivor区
dng->from()->object_iterate_careful(&sss_cl);
dng->to()->object_iterate_careful(&sss_cl);
}
MarkRefsIntoAndScanClosure
mrias_cl(_span, ref_processor(), &_markBitMap, &_modUnionTable,
&_markStack, this, CMSYield,
true /* precleaning phase */);
ScanMarkedObjectsAgainCarefullyClosure
smoac_cl(this, _span,
&_markBitMap, &_markStack, &mrias_cl, CMSYield);
//CMSPrecleanIter的默认值是3
assert(CMSPrecleanIter < 10, "CMSPrecleanIter is too large");
//CMSPrecleanNumerator的默认值是2,CMSPrecleanDenominator的默认值是3
assert(CMSPrecleanNumerator < CMSPrecleanDenominator,
"Bad convergence multiplier");
//CMSPrecleanThreshold的默认值是1000
assert(CMSPrecleanThreshold >= 100,
"Unreasonably low CMSPrecleanThreshold");
//lastNumCards表示上一次遍历找到的脏的卡表数
//curNumCards表示当前遍历找到的脏的卡表数
//cumNumCards表示累加的找到的脏的卡表数
size_t numIter, cumNumCards, lastNumCards, curNumCards;
for (numIter = 0, cumNumCards = lastNumCards = curNumCards = 0;
numIter < CMSPrecleanIter;
numIter++, lastNumCards = curNumCards, cumNumCards += curNumCards) {
//遍历mod_union_table中被打标的位,即遍历卡表项是脏的内存空间中的对象
curNumCards = preclean_mod_union_table(_cmsGen, &smoac_cl);
if (Verbose && PrintGCDetails) {
gclog_or_tty->print(" (modUnionTable: %d cards)", curNumCards);
}
//如果找到的脏的卡表数小于阈值 或者当前遍历找到的脏的卡表数大于上一次遍历的2/3,则终止遍历
if (curNumCards <= CMSPrecleanThreshold ||
(numIter > 0 &&
(curNumCards * CMSPrecleanDenominator >
lastNumCards * CMSPrecleanNumerator))) {
numIter++;
cumNumCards += curNumCards;
break;
}
}
//遍历加载的所有Klass
preclean_klasses(&mrias_cl, _cmsGen->freelistLock());
//遍历老年代对应的卡表区域,找到所有脏的卡表项
curNumCards = preclean_card_table(_cmsGen, &smoac_cl);
cumNumCards += curNumCards;
if (PrintGCDetails && PrintCMSStatistics != 0) {
gclog_or_tty->print_cr(" (cardTable: %d cards, re-scanned %d cards, %d iterations)",
curNumCards, cumNumCards, numIter);
}
//返回总共遍历处理的卡表项的数量
return cumNumCards; // as a measure of useful work done
}
void CMSCollector::abortable_preclean() {
//校验调用线程是否正确
check_correct_thread_executing();
//校验CMSPrecleaningEnabled为true,该配置项默认为true
assert(CMSPrecleaningEnabled, "Inconsistent control state");
assert(_collectorState == AbortablePreclean, "Inconsistent control state");
//如果eden区已使用内存大于CMSScheduleRemarkEdenSizeThreshold,该属性默认为2M
if (get_eden_used() > CMSScheduleRemarkEdenSizeThreshold) {
TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty);
CMSPhaseAccounting pa(this, "abortable-preclean", _gc_tracer_cm->gc_id(), !PrintGCDetails);
size_t loops = 0, workdone = 0, cumworkdone = 0, waited = 0;
//不断循环直到这两个条件有一个为true
while (!(should_abort_preclean() ||
ConcurrentMarkSweepThread::should_terminate())) {
//CMSPrecleanRefLists2表示是否清理Reference实例,默认为false
//CMSPrecleanSurvivors2表示是否清理Survivor区,默认为true
//preclean_work返回累积清理的卡表项的个数
workdone = preclean_work(CMSPrecleanRefLists2, CMSPrecleanSurvivors2);
cumworkdone += workdone;
loops++;
//CMSMaxAbortablePrecleanLoops表示循环的最大次数,默认为0
if ((CMSMaxAbortablePrecleanLoops != 0) &&
loops >= CMSMaxAbortablePrecleanLoops) {
if (PrintGCDetails) {
gclog_or_tty->print(" CMS: abort preclean due to loops ");
}
break;
}
//CMSMaxAbortablePrecleanTime表示AbortablePreclean的最大时间,默认是5000,单位毫秒
if (pa.wallclock_millis() > CMSMaxAbortablePrecleanTime) {
if (PrintGCDetails) {
gclog_or_tty->print(" CMS: abort preclean due to time ");
}
break;
}
//CMSAbortablePrecleanMinWorkPerIteration默认是100,如果清理的脏的卡表数小于该值则应该等待
if (workdone < CMSAbortablePrecleanMinWorkPerIteration) {
stopTimer();
//在CGC_lock上等待最多CMSAbortablePrecleanWaitMillis毫秒,该属性默认值是100
cmsThread()->wait_on_cms_lock(CMSAbortablePrecleanWaitMillis);
startTimer();
waited++;
}
}
if (PrintCMSStatistics > 0) {
gclog_or_tty->print(" [%d iterations, %d waits, %d cards)] ",
loops, waited, cumworkdone);
}
}
//退出循环,获取CMS Token,将状态置为FinalMarking
CMSTokenSync x(true); // is cms thread
if (_collectorState != Idling) {
assert(_collectorState == AbortablePreclean,
"Spontaneous state transition?");
_collectorState = FinalMarking;
} // Else, a foreground collection completed this CMS cycle.
return;
}
inline size_t CMSCollector::get_eden_used() const {
return _young_gen->as_DefNewGeneration()->eden()->used();
}
void ConcurrentMarkSweepThread::wait_on_cms_lock(long t_millis) {
MutexLockerEx x(CGC_lock,
Mutex::_no_safepoint_check_flag);
if (_should_terminate || _collector->_full_gc_requested) {
return;
}
set_CMS_flag(CMS_cms_wants_token); // to provoke notifies
CGC_lock->wait(Mutex::_no_safepoint_check_flag, t_millis);
clear_CMS_flag(CMS_cms_wants_token);
assert(!CMS_flag_is_set(CMS_cms_has_token | CMS_cms_wants_token),
"Should not be set");
}
7、CMSKeepAliveClosure
CMSKeepAliveClosure用来将某个oop标记成存活的,是预处理查找到的Reference实例调用的,其实现如下:
CMSKeepAliveClosure::CMSKeepAliveClosure( CMSCollector* collector,
MemRegion span,
CMSBitMap* bit_map, CMSMarkStack* mark_stack,
bool cpc):
_collector(collector),
_span(span),
_bit_map(bit_map),
_mark_stack(mark_stack),
_concurrent_precleaning(cpc) { //preclean和abortable_preclean都传true
assert(!_span.is_empty(), "Empty span could spell trouble");
}
void CMSKeepAliveClosure::do_oop(oop obj) {
HeapWord* addr = (HeapWord*)obj;
//如果addr在堆内存中,且未标记
if (_span.contains(addr) &&
!_bit_map->isMarked(addr)) {
//将其打标
_bit_map->mark(addr);
bool simulate_overflow = false;
if (simulate_overflow || !_mark_stack->push(obj)) {
//如果_mark_stack->push为false,即_mark_stack已经满了
if (_concurrent_precleaning) {
//_concurrent_precleaning为true,表示执行预处理,否则的话将其放到overflow_list中
//校验_overflow_list是NULL
assert(_collector->overflow_list_is_empty(), "Error");
if (obj->is_objArray()) {
size_t sz = obj->size();
//数组的终止地址按card_size对齐
HeapWord* end_card_addr =
(HeapWord*)round_to((intptr_t)(addr+sz), CardTableModRefBS::card_size);
MemRegion redirty_range = MemRegion(addr, end_card_addr);
assert(!redirty_range.is_empty(), "Arithmetical tautology");
//将数组对应的内存区域在_modUnionTable中打标
_collector->_modUnionTable.mark_range(redirty_range);
} else {
_collector->_modUnionTable.mark(addr);
}
_collector->_ser_kac_preclean_ovflw++;
} else {
//_concurrent_precleaning为false
_collector->push_on_overflow_list(obj);
_collector->_ser_kac_ovflw++;
}
}
}
}
void CMSCollector::push_on_overflow_list(oop p) {
NOT_PRODUCT(_num_par_pushes++;)
assert(p->is_oop(), "Not an oop");
//如果对象头中包含重要信息则将其对象头和oop保存到对应的stack中
preserve_mark_if_necessary(p);
//通过对象头地址构成一个链表
p->set_mark((markOop)_overflow_list);
_overflow_list = p;
}
void CMSCollector::preserve_mark_if_necessary(oop p) {
markOop m = p->mark();
if (m->must_be_preserved(p)) {
preserve_mark_work(p, m);
}
}
void CMSCollector::preserve_mark_work(oop p, markOop m) {
_preserved_oop_stack.push(p);
_preserved_mark_stack.push(m);
assert(m == p->mark(), "Mark word changed");
assert(_preserved_oop_stack.size() == _preserved_mark_stack.size(),
"bijection");
}
8、CMSDrainMarkingStackClosure
CMSDrainMarkingStackClosure是某一类型的Reference实例都preclean完成后调用的,用来处理CMSKeepAliveClosure放在_overflow_list中的待处理oop,会不断的从_overflow_list中取出一定数量的oop,然后遍历该oop所引用的其他对象,通过CMSKeepAliveClosure来处理所引用的其他对象,即将该对象所引用的其他对象也都标记成存活的。
CMSDrainMarkingStackClosure(CMSCollector* collector, MemRegion span,
CMSBitMap* bit_map, CMSMarkStack* mark_stack,
CMSKeepAliveClosure* keep_alive,
bool cpc):
_collector(collector),
_span(span),
_bit_map(bit_map),
_mark_stack(mark_stack),
_keep_alive(keep_alive),
_concurrent_precleaning(cpc) {
assert(_concurrent_precleaning == _keep_alive->concurrent_precleaning(),
"Mismatch");
}
void CMSDrainMarkingStackClosure::do_void() {
//取_mark_stack容量的4分之一作为一次从_mark_stack中取出oop的个数
const size_t num = _mark_stack->capacity()/4;
//如果_concurrent_precleaning为false,则CMSKeepAliveClosure会将处理的oop放到overflow_list,overflow_list肯定非空
assert(!_concurrent_precleaning || _collector->overflow_list_is_empty(),
"Overflow list should be NULL during concurrent phases");
//
while (!_mark_stack->isEmpty() || //_mark_stack非空
//如果_mark_stack是空的,则从overflow_list中取出最多num个放入_mark_stack中
_collector->take_from_overflow_list(num, _mark_stack)) {
//弹出一个待处理的oop
oop obj = _mark_stack->pop();
HeapWord* addr = (HeapWord*)obj;
assert(_span.contains(addr), "Should be within span");
//校验在其BitMap中已打标,打标动作在CMSKeepAliveClosure中完成的
assert(_bit_map->isMarked(addr), "Should be marked");
assert(obj->is_oop(), "Should be an oop");
//遍历该对象所引用的其他对象
obj->oop_iterate(_keep_alive);
}
}
bool CMSCollector::take_from_overflow_list(size_t num, CMSMarkStack* stack) {
assert(stack->isEmpty(), "Expected precondition");
assert(stack->capacity() > num, "Shouldn't bite more than can chew");
size_t i = num;
oop cur = _overflow_list;
const markOop proto = markOopDesc::prototype();
//不断遍历直到取出了num个oop
for (oop next; i > 0 && cur != NULL; cur = next, i--) {
//从对象头中取出下一个待处理的oop的地址
next = oop(cur->mark());
//恢复初始的对象头
cur->set_mark(proto); // until proven otherwise
assert(cur->is_oop(), "Should be an oop");
//将cur放入CMSMarkStack中
bool res = stack->push(cur);
assert(res, "Bit off more than can chew?");
}
//重置_overflow_list
_overflow_list = cur;
return !stack->isEmpty();
}
9、CMSPrecleanRefsYieldClosure
CMSPrecleanRefsYieldClosure是每次开始处理一个Reference实例数组时调用的,用来判断是否应该yield,如果需要则执行yield,判断是否需要终止执行,如果前台GC被激活则返回true,调用方负责终止处理。
CMSPrecleanRefsYieldClosure(CMSCollector* collector):
_collector(collector) {}
bool CMSPrecleanRefsYieldClosure::should_return() {
if (ConcurrentMarkSweepThread::should_yield()) {
//如果需要CMS Thread执行yeild 则让出CPU执行
do_yield_work();
}
//如果前台GC被激活则返回true,返回true以后Reference处理就会停止
return _collector->foregroundGCIsActive();
}
网友评论