目录
2、Par_MarkRefsIntoAndScanClosure
6、ScanMarkedObjectsAgainClosure
本篇继续上一篇《Hotspot 垃圾回收之CMSCollector(四) 源码解析》讲解FinalMarking和Sweeping步骤的相关实现。
1、CMSParRemarkTask
CMSParRemarkTask用于并行的执行再次标记,是do_remark_parallel方法的核心,其实现如下:
CMSParRemarkTask(CMSCollector* collector,
CompactibleFreeListSpace* cms_space,
int n_workers, FlexibleWorkGang* workers,
OopTaskQueueSet* task_queues):
CMSParMarkTask("Rescan roots and grey objects in parallel",
collector, n_workers),
_cms_space(cms_space),
_task_queues(task_queues),
_term(n_workers, task_queues) { }
void CMSParRemarkTask::work(uint worker_id) {
elapsedTimer _timer;
ResourceMark rm;
HandleMark hm;
// ---------- rescan from roots --------------
_timer.start();
GenCollectedHeap* gch = GenCollectedHeap::heap();
Par_MarkRefsIntoAndScanClosure par_mrias_cl(_collector,
_collector->_span, _collector->ref_processor(),
&(_collector->_markBitMap),
work_queue(worker_id));
//遍历年轻代的对象
{
work_on_young_gen_roots(worker_id, &par_mrias_cl);
_timer.stop();
if (PrintCMSStatistics != 0) {
gclog_or_tty->print_cr(
"Finished young gen rescan work in %dth thread: %3.3f sec",
worker_id, _timer.seconds());
}
}
// ---------- remaining roots --------------
_timer.reset();
_timer.start();
//遍历Universe,SystemDictionary,StringTable等类中包含的oop
gch->gen_process_roots(_collector->_cmsGen->level(),
false, // yg was scanned above
false, // this is parallel code
GenCollectedHeap::ScanningOption(_collector->CMSCollector::roots_scanning_options()),
_collector->should_unload_classes(),
&par_mrias_cl,
NULL,
NULL); // The dirty klasses will be handled below
assert(_collector->should_unload_classes()
|| (_collector->CMSCollector::roots_scanning_options() & GenCollectedHeap::SO_AllCodeCache),
"if we didn't scan the code cache, we have to be ready to drop nmethods with expired weak oops");
_timer.stop();
if (PrintCMSStatistics != 0) {
gclog_or_tty->print_cr(
"Finished remaining root rescan work in %dth thread: %3.3f sec",
worker_id, _timer.seconds());
}
// ---------- unhandled CLD scanning ----------
if (worker_id == 0) { //只需要worker_id等于0的这一个线程处理即可
_timer.reset();
_timer.start();
//遍历新增的ClassLoaderData
ResourceMark rm;
GrowableArray<ClassLoaderData*>* array = ClassLoaderDataGraph::new_clds();
for (int i = 0; i < array->length(); i++) {
par_mrias_cl.do_class_loader_data(array->at(i));
}
ClassLoaderDataGraph::remember_new_clds(false);
_timer.stop();
if (PrintCMSStatistics != 0) {
gclog_or_tty->print_cr(
"Finished unhandled CLD scanning work in %dth thread: %3.3f sec",
worker_id, _timer.seconds());
}
}
// ---------- dirty klass scanning ----------
if (worker_id == 0) { //只需要worker_id等于0的这一个线程处理即可
_timer.reset();
_timer.start();
//遍历所有的ClassLoaderData
RemarkKlassClosure remark_klass_closure(&par_mrias_cl);
ClassLoaderDataGraph::classes_do(&remark_klass_closure);
_timer.stop();
if (PrintCMSStatistics != 0) {
gclog_or_tty->print_cr(
"Finished dirty klass scanning work in %dth thread: %3.3f sec",
worker_id, _timer.seconds());
}
}
// ---------- rescan dirty cards ------------
_timer.reset();
_timer.start();
//遍历脏的卡表
do_dirty_card_rescan_tasks(_cms_space, worker_id, &par_mrias_cl);
_timer.stop();
if (PrintCMSStatistics != 0) {
gclog_or_tty->print_cr(
"Finished dirty card rescan work in %dth thread: %3.3f sec",
worker_id, _timer.seconds());
}
// ---------- steal work from other threads ...
// ---------- ... and drain overflow list.
_timer.reset();
_timer.start();
do_work_steal(worker_id, &par_mrias_cl, _collector->hash_seed(worker_id));
_timer.stop();
if (PrintCMSStatistics != 0) {
gclog_or_tty->print_cr(
"Finished work stealing in %dth thread: %3.3f sec",
worker_id, _timer.seconds());
}
}
void
CMSParRemarkTask::do_dirty_card_rescan_tasks(
CompactibleFreeListSpace* sp, int i,
Par_MarkRefsIntoAndScanClosure* cl) {
ResourceMark rm;
HandleMark hm;
OopTaskQueue* work_q = work_queue(i);
ModUnionClosure modUnionClosure(&(_collector->_modUnionTable));
//full_span对应完整的老年代空间
MemRegion full_span = _collector->_span;
CMSBitMap* bm = &(_collector->_markBitMap); // shared
MarkFromDirtyCardsClosure
greyRescanClosure(_collector, full_span, // entire span of interest
sp, bm, work_q, cl);
SequentialSubTasksDone* pst = sp->conc_par_seq_tasks();
assert(pst->valid(), "Uninitialized use?");
uint nth_task = 0;
const int alignment = CardTableModRefBS::card_size * BitsPerWord;
MemRegion span = sp->used_region();
HeapWord* start_addr = span.start();
HeapWord* end_addr = (HeapWord*)round_to((intptr_t)span.end(),
alignment);
const size_t chunk_size = sp->rescan_task_size(); // in HeapWord units
assert((HeapWord*)round_to((intptr_t)start_addr, alignment) ==
start_addr, "Check alignment");
assert((size_t)round_to((intptr_t)chunk_size, alignment) ==
chunk_size, "Check alignment");
//is_task_claimed方法会原子的改变nth_task的值
while (!pst->is_task_claimed(/* reference */ nth_task)) {
//计算遍历的内存区域
MemRegion this_span = MemRegion(start_addr + nth_task*chunk_size,
start_addr + (nth_task+1)*chunk_size);
if (this_span.end() > end_addr) {
//不能超过end_addr
this_span.set_end(end_addr);
assert(!this_span.is_empty(), "Program logic (calculation of n_tasks)");
}
//不断遍历,找到一段连续的脏的卡表项,将其对应的内存区域在modUnionTable中打标,
_collector->_ct->ct_bs()->dirty_card_iterate(this_span,
&modUnionClosure);
//不断遍历,找到一段连续的被打标的位,使用greyRescanClosure来遍历对应的内存区域中的对象
_collector->_modUnionTable.dirty_range_iterate_clear(
this_span, &greyRescanClosure);
_collector->_modUnionTable.verifyNoOneBitsInRange(
this_span.start(),
this_span.end());
}
pst->all_tasks_completed(); //标记线程执行结束
}
void
CMSParRemarkTask::do_work_steal(int i, Par_MarkRefsIntoAndScanClosure* cl,
int* seed) {
OopTaskQueue* work_q = work_queue(i);
NOT_PRODUCT(int num_steals = 0;)
oop obj_to_scan;
CMSBitMap* bm = &(_collector->_markBitMap);
while (true) {
//遍历work_queue中的oop
cl->trim_queue(0);
//ParGCDesiredObjsFromOverflowList的默认值是20,计算从overflow_list中取出待处理oop的个数
size_t num_from_overflow_list = MIN2((size_t)(work_q->max_elems() - work_q->size())/4,
(size_t)ParGCDesiredObjsFromOverflowList);
//从overflow_list中最多哦取出num_from_overflow_list个放入work_q
if (_collector->par_take_from_overflow_list(num_from_overflow_list,
work_q,
ParallelGCThreads)) {
//取出成功,不需要从其他线程的work_queue中偷待处理的oop
continue;
}
assert(work_q->size() == 0, "Have work, shouldn't steal");
//尝试从其他work_queue中偷一个待处理的oop
if (task_queues()->steal(i, seed, /* reference */ obj_to_scan)) {
assert(obj_to_scan->is_oop(), "Oops, not an oop!");
assert(bm->isMarked((HeapWord*)obj_to_scan), "Stole an unmarked oop?");
//遍历该oop所引用的其他oop
obj_to_scan->oop_iterate(cl);
} else if (terminator()->offer_termination()) {
//没有偷到,其他线程的work_queue也是空的,尝试几次后则终止循环
break;
}
}
assert(work_q->size() == 0 && _collector->overflow_list_is_empty(),
"Else our work is not yet done");
}
bool CMSCollector::par_take_from_overflow_list(size_t num,
OopTaskQueue* work_q,
int no_of_gc_threads) {
//校验work_q是空的
assert(work_q->size() == 0, "First empty local work queue");
assert(num < work_q->max_elems(), "Can't bite more than we can chew");
if (_overflow_list == NULL) {
//_overflow_list是空的
return false;
}
//BUSY是一个特殊的实际并不存在的一个地址
oop prefix = cast_to_oop(Atomic::xchg_ptr(BUSY, &_overflow_list));
Thread* tid = Thread::current();
size_t CMSOverflowSpinCount = (size_t) no_of_gc_threads; // was ParallelGCThreads;
size_t sleep_time_millis = MAX2((size_t)1, num/100);
// If the list is busy, we spin for a short while,
// sleeping between attempts to get the list.
for (size_t spin = 0; prefix == BUSY && spin < CMSOverflowSpinCount; spin++) {
os::sleep(tid, sleep_time_millis, false);
if (_overflow_list == NULL) {
//为空,表示_overflow_list已经空了
return false;
} else if (_overflow_list != BUSY) {
//不等于BUSY说明里面有待处理的oop,则尝试抢占,如果抢占成功,prefix就是之前的_overflow_list
//然后_overflow_list变成BUSY,等待Closure往里面放待处理的oop
prefix = cast_to_oop(Atomic::xchg_ptr(BUSY, &_overflow_list));
}
}
//遍历结束,要么达到CMSOverflowSpinCount次数限制,要么prefix是非BUSY
if (prefix == NULL || prefix == BUSY) {
//达到次数限制了
if (prefix == NULL) {
//将_overflow_list由BUSY置为NULL
(void) Atomic::cmpxchg_ptr(NULL, &_overflow_list, BUSY);
}
return false;
}
assert(prefix != NULL && prefix != BUSY, "Error");
size_t i = num;
//因为_overflow_list是通过对象头指针构成的链表,所以拿到了_overflow_list就意味着拿到了整个链表
oop cur = prefix;
//往后遍历,找到最后一个需要取出的oop
for (; i > 1 && cur->mark() != NULL; cur = oop(cur->mark()), i--);
if (cur->mark() == NULL) {
//_overflow_list被全部取完了
if (_overflow_list == BUSY) {
//将_overflow_list由BUSY置为NULL