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
(void) Atomic::cmpxchg_ptr(NULL, &_overflow_list, BUSY);
}
} else {
//_overflow_list还有多余的,需要将其归还
assert(cur->mark() != BUSY, "Error");
oop suffix_head = cur->mark(); // suffix will be put back on global list
cur->set_mark(NULL); // break off suffix
oop observed_overflow_list = _overflow_list;
oop cur_overflow_list = observed_overflow_list;
bool attached = false;
//当前_overflow_list还是空的,就尝试将suffix_head设置为_overflow_list
while (observed_overflow_list == BUSY || observed_overflow_list == NULL) {
//原子的修改_overflow_list,尝试将suffix_head设置为_overflow_list
observed_overflow_list =
(oop) Atomic::cmpxchg_ptr(suffix_head, &_overflow_list, cur_overflow_list);
if (cur_overflow_list == observed_overflow_list) {
//修改成功,归还成功
attached = true;
break;
} else cur_overflow_list = observed_overflow_list;
}
//while循环结束,说明有线程往_overflow_list放了一个对象,需要
if (!attached) {
//一直向后遍历找到最后一个元素
for (cur = suffix_head; cur->mark() != NULL; cur = (oop)(cur->mark()));
oop suffix_tail = cur;
assert(suffix_tail != NULL && suffix_tail->mark() == NULL,
"Tautology");
observed_overflow_list = _overflow_list;
do {
cur_overflow_list = observed_overflow_list;
if (cur_overflow_list != BUSY) {
//将最后一个元素插入到当前overflow_list的前面
suffix_tail->set_mark(markOop(cur_overflow_list));
} else { // cur_overflow_list == BUSY,即overflow_list是空的
suffix_tail->set_mark(NULL);
}
//原子新修改_overflow_list为suffix_head,直到修改成功,退出循环
observed_overflow_list =
(oop) Atomic::cmpxchg_ptr(suffix_head, &_overflow_list, cur_overflow_list);
} while (cur_overflow_list != observed_overflow_list);
}
}
assert(prefix != NULL, "control point invariant");
const markOop proto = markOopDesc::prototype();
oop next;
//将prefix到cur之间的oop放入work_q
for (cur = prefix; cur != NULL; cur = next) {
next = oop(cur->mark());
//恢复成初始的对象头
cur->set_mark(proto); // until proven otherwise
assert(cur->is_oop(), "Should be an oop");
bool res = work_q->push(cur);
assert(res, "Bit off more than we can chew?");
NOT_PRODUCT(n++;)
}
return true;
}
2、Par_MarkRefsIntoAndScanClosure
Par_MarkRefsIntoAndScanClosure是CMSParRemarkTask的核心Closure实现,年轻代,Universe/SystemDictionary等组件,新创建的ClassLoaderData,脏的klass和卡表都依赖其遍历相关oop,遍历时如果该oop为标记,则将其再bitMap中打标,然后以该oop为根节点,不断向上遍历其所有引用的oop,直到所有oop遍历完成,其实现如下:
Par_MarkRefsIntoAndScanClosure::Par_MarkRefsIntoAndScanClosure(
CMSCollector* collector, MemRegion span, ReferenceProcessor* rp,
CMSBitMap* bit_map, OopTaskQueue* work_queue):
_span(span),
_bit_map(bit_map),
_work_queue(work_queue),
//计算阈值,遍历时会不断从work_queue中取出待处理的oop,直到work_queue中剩余的oop个数低于该值
_low_water_mark(MIN2((uint)(work_queue->max_elems()/4),
(uint)(CMSWorkQueueDrainThreshold * ParallelGCThreads))), //CMSWorkQueueDrainThreshold的默认值是10
_par_pushAndMarkClosure(collector, span, rp, bit_map, work_queue)
{
_ref_processor = rp;
assert(_ref_processor != NULL, "_ref_processor shouldn't be NULL");
}
void Par_MarkRefsIntoAndScanClosure::do_oop(oop obj) {
if (obj != NULL) {
assert(obj->is_oop(true), "expected an oop");
HeapWord* addr = (HeapWord*)obj;
if (_span.contains(addr) &&
!_bit_map->isMarked(addr)) {
//如果未打标
if (_bit_map->par_mark(addr)) {
//如果bitMap打标成功,如果失败说明已经有某个线程打标了
//将其加入到队列中
bool res = _work_queue->push(obj);
assert(res, "Low water mark should be less than capacity?");
trim_queue(_low_water_mark);
} // Else, another thread claimed the object
}
}
}
inline void Par_MarkRefsIntoAndScanClosure::trim_queue(uint max) {
while (_work_queue->size() > max) {
oop newOop;
if (_work_queue->pop_local(newOop)) {
assert(newOop->is_oop(), "Expected an oop");
assert(_bit_map->isMarked((HeapWord*)newOop),
"only grey objects on this stack");
//取出_work_queue中的oop,遍历其所引用的其他oop
//_par_pushAndMarkClosure在处理其他oop时,会把其他oop所引用的oop同样放到_work_queue中
newOop->oop_iterate(&_par_pushAndMarkClosure);
}
}
}
//Par_MarkRefsIntoAndScanClosure继承自MetadataAwareOopsInGenClosure
//do_class_loader_data方法使用父类的实现
inline void MetadataAwareOopsInGenClosure::do_class_loader_data(ClassLoaderData* cld) {
assert(_klass_closure._oop_closure == this, "Must be");
bool claim = true; //确保ClassLoaderData不会被二次遍历
//_klass_closure._oop_closure实际就是当前子类Par_MarkRefsIntoAndScanClosure
//_klass_closure就是KlassToOopClosure,遍历klass实际就是拿_oop_closure来遍历Klass对应的类Class实例
cld->oops_do(_klass_closure._oop_closure, &_klass_closure, claim);
}
3、Par_PushAndMarkClosure
Par_PushAndMarkClosure是Par_MarkRefsIntoAndScanClosure中用来处理某个找到的oop所引用的其他oop,实现以某个找到的oop为根节点的树形查找效果,其实现如下:
Par_PushAndMarkClosure::Par_PushAndMarkClosure(CMSCollector* collector,
MemRegion span,
ReferenceProcessor* rp,
CMSBitMap* bit_map,
OopTaskQueue* work_queue):
MetadataAwareOopClosure(rp),
_collector(collector),
_span(span),
_bit_map(bit_map),
_work_queue(work_queue)
{
assert(_ref_processor != NULL, "_ref_processor shouldn't be NULL");
}
void Par_PushAndMarkClosure::do_oop(oop obj) {
assert(obj->is_oop_or_null(true),
"expected an oop or NULL");
HeapWord* addr = (HeapWord*)obj;
if (_span.contains(addr) && !_bit_map->isMarked(addr)) {
//如果未标记
if (_bit_map->par_mark(addr)) { // ... now grey
//如果打标成功
bool simulate_overflow = false;
//将其放到_work_queue中
if (simulate_overflow || !_work_queue->push(obj)) {
//如果_work_queue满了,push失败,则将其放到overflow_list中
_collector->par_push_on_overflow_list(obj);
//增加计数
_collector->_par_pmc_remark_ovflw++; // imprecise OK: no need to CAS
}
}
}
}
void CMSCollector::par_push_on_overflow_list(oop p) {
NOT_PRODUCT(Atomic::inc_ptr(&_num_par_pushes);)
assert(p->is_oop(), "Not an oop");
par_preserve_mark_if_necessary(p);
oop observed_overflow_list = _overflow_list;
oop cur_overflow_list;
do {
cur_overflow_list = observed_overflow_list;
if (cur_overflow_list != BUSY) {
//不等于BUSY说明已经有元素了,将其插入到cur_overflow_list的前面
p->set_mark(markOop(cur_overflow_list));
} else {
p->set_mark(NULL);
}
//原子的修改_overflow_list,如果修改成功则退出循环
observed_overflow_list =
(oop) Atomic::cmpxchg_ptr(p, &_overflow_list, cur_overflow_list);
} while (cur_overflow_list != observed_overflow_list);
}
4、RemarkKlassClosure
RemarkKlassClosure用来遍历所有已加载的Klass,其底层就是遍历Klass对应的ClassLoaderData,如果已经遍历过一遍了就不会二次遍历,其实现如下:
class RemarkKlassClosure : public KlassClosure {
KlassToOopClosure _cm_klass_closure;
public:
RemarkKlassClosure(OopClosure* oop_closure) : _cm_klass_closure(oop_closure) {}
void do_klass(Klass* k) {
if (k->has_accumulated_modified_oops()) {
//清除accumulated_modified_oops标识
k->clear_accumulated_modified_oops();
} else if (k->has_modified_oops()) {
//年轻代遍历时需要该属性,这里不处理
} else {
//没有修改不做处理
return;
}
//遍历该Klass
_cm_klass_closure.do_klass(k);
}
};
//Par_MarkRefsIntoAndScanClosure继承MetadataAwareOopsInGenClosure,采用父类do_klass的实现
inline void MetadataAwareOopsInGenClosure::do_klass(Klass* k) { do_klass_nv(k); }
inline void MetadataAwareOopsInGenClosure::do_klass_nv(Klass* k) {
ClassLoaderData* cld = k->class_loader_data();
//实际遍历该Klass对应的ClassLoaderData
do_class_loader_data(cld);
}
5、MarkFromDirtyCardsClosure
MarkFromDirtyCardsClosure是modUnionTable.dirty_range_iterate_clear方法用来遍历一段连续的脏的位对应的内存空间中包含的对象,具体的对象处理逻辑封装在ScanMarkedObjectsAgainClosure,其实现如下:
//非并行GC使用
MarkFromDirtyCardsClosure(CMSCollector* collector,
MemRegion span,
CompactibleFreeListSpace* space,
CMSBitMap* bit_map,
CMSMarkStack* mark_stack,
MarkRefsIntoAndScanClosure* cl):
_space(space),
_num_dirty_cards(0),
_scan_cl(collector, span, collector->ref_processor(), bit_map, /_scan_cl就是ScanMarkedObjectsAgainClosure,同样支持并行和非并行两种
mark_stack, cl) { }
//并行GC使用,多了一个work_queue
MarkFromDirtyCardsClosure(CMSCollector* collector,
MemRegion span,
CompactibleFreeListSpace* space,
CMSBitMap* bit_map,
OopTaskQueue* work_queue,
Par_MarkRefsIntoAndScanClosure* cl):
_space(space),
_num_dirty_cards(0),
_scan_cl(collector, span, collector->ref_processor(), bit_map,
work_queue, cl) { }
//传入mr是modUnionTable中一段连续的打标的位对应的地址段
void MarkFromDirtyCardsClosure::do_MemRegion(MemRegion mr) {
assert(((size_t)mr.start())%CardTableModRefBS::card_size_in_words == 0,
"mr should be aligned to start at a card boundary");
if (PrintCMSStatistics != 0) {
_num_dirty_cards +=
mr.word_size()/CardTableModRefBS::card_size_in_words;
}
//使用_scan_cl来遍历mr中的对象
_space->object_iterate_mem(mr, &_scan_cl);
}
6、ScanMarkedObjectsAgainClosure
ScanMarkedObjectsAgainClosure同MarkFromDirtyCardsClosure一样,支持并行和单线程执行两个构造方法,对于传进来的oop,如果该oop已经在BitMap中打标则使用Par_MarkRefsIntoAndScanClosure或者MarkRefsIntoAndScanClosure遍历该oop所引用的其他oop,即以该oop为根节点遍历所有引用的其他oop。其实现如下:
//非并行GC使用
ScanMarkedObjectsAgainClosure(CMSCollector* collector,
MemRegion span,
ReferenceProcessor* rp,
CMSBitMap* bit_map,
CMSMarkStack* mark_stack,
MarkRefsIntoAndScanClosure* cl):
_parallel(false),
_bit_map(bit_map),
_scan_closure(cl) { } //_scan_closure和_par_scan_closure两个是一个union属性
//并行GC使用
ScanMarkedObjectsAgainClosure(CMSCollector* collector,
MemRegion span,
ReferenceProcessor* rp,
CMSBitMap* bit_map,
OopTaskQueue* work_queue,
Par_MarkRefsIntoAndScanClosure* cl):
_parallel(true),
_bit_map(bit_map),
_par_scan_closure(cl) { }
bool ScanMarkedObjectsAgainClosure::do_object_bm(oop p, MemRegion mr) {
// Ignore mark word because we are running concurrent with mutators
assert(p->is_oop_or_null(true), "expected an oop or null");
HeapWord* addr = (HeapWord*)p;
assert(_span.contains(addr), "we are scanning the CMS generation");
bool is_obj_array = false;
if (_bit_map->isMarked(addr)) {
if (p->is_objArray()) {
//如果是对象数组
is_obj_array = true;
if (_parallel) {
//并行遍历该对象所引用的其他对象
p->oop_iterate(_par_scan_closure, mr);
} else {
//单线程遍历
p->oop_iterate(_scan_closure, mr);
}
} else {
//如果是普通对象
if (_parallel) {
p->oop_iterate(_par_scan_closure);
} else {
p->oop_iterate(_scan_closure);
}
}
}
//返回p是否是对象数组,只有p在bitMap中打标了且是对象数组的情况下才会返回true
return is_obj_array;
}
7、FinalMarking 步骤总结
FinalMarking和InitialMarking一样都要求JVM处于安全点的状态,即必须stop the world,顾名思义,InitialMarking是初始的第一遍标记,FinalMarking是最终的第二遍标记,事实上FinalMarking只有在后台GC执行了InitialMarking步骤的情形下才会执行,如果是前台GC执行的InitialMarking步骤则不需要再次执行FinalMarking,这是因为前台GC执行的整个过程都会stop the world,而后台GC只有在执行InitialMarking和FinalMarking这两个步骤时才会stop the world,在这两个步骤中间对象的引用关系都可能发生改变,所以需要再次标记。再次标记的内容和初始标记的内容基本相同,主要多了一项对脏的卡表项和modUnionTable中被打标的位对应的内存区域中包含的对象的遍历。FinalMarking除二次标记之外,还需要完成Reference实例的清理并将其加入到Reference维护的pend_list中,如果需要卸载类相关的元数据,还要清理SystemDictionary,CodeCache,SymbolTable,StringTable等组件中不再使用的资源。
8、sweep
sweep方法用于处理Sweeping步骤,其核心在SweepClosure,因为老年代清理过程中必须获取CMS Token,freelistLock和bitMapLock锁,,所以整个过程都是单线程执行的,其实现如下:
void CMSCollector::sweep(bool asynch) {
assert(_collectorState == Sweeping, "just checking");
//校验当前线程的正确性
check_correct_thread_executing();
//校验_markStack和overflow_list是空的
verify_work_stacks_empty();
verify_overflow_empty();
//增加sweep_count计数
increment_sweep_count();
TraceCMSMemoryManagerStats tms(_collectorState,GenCollectedHeap::heap()->gc_cause());
_inter_sweep_timer.stop();
//采样,记录耗时
_inter_sweep_estimate.sample(_inter_sweep_timer.seconds());
size_policy()->avg_cms_free_at_sweep()->sample(_cmsGen->free());
assert(!_intra_sweep_timer.is_active(), "Should not be active");
//_intra_sweep_timer计时器重置
_intra_sweep_timer.reset();
_intra_sweep_timer.start();
if (asynch) {
//如果是异步GC
//TraceCPUTime和CMSPhaseAccounting都是打印日志IDE
TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty);
CMSPhaseAccounting pa(this, "sweep", _gc_tracer_cm->gc_id(), !PrintGCDetails);
{
//获取CMS Token,freelistLock和bitMapLock锁
CMSTokenSyncWithLocks ts(true, _cmsGen->freelistLock(),
bitMapLock());
//清理老年代
sweepWork(_cmsGen, asynch);
}
{
//获取CMS Token,freelistLock锁
CMSTokenSyncWithLocks ts(true, _cmsGen->freelistLock());
//更新heap_info
Universe::update_heap_info_at_gc();
_collectorState = Resizing;
}
} else {
//已经获取了相关锁,直接执行清理
sweepWork(_cmsGen, asynch);
//更新heap_info
Universe::update_heap_info_at_gc();
_collectorState = Resizing;
}
verify_work_stacks_empty();
verify_overflow_empty();
if (should_unload_classes()) {
//设置_should_purge属性为true,下一次进入安全点会清理掉需要卸载的类的相关元数据
ClassLoaderDataGraph::set_should_purge(true);
}
//_intra_sweep_timer计时器停止
_intra_sweep_timer.stop();
//采样,记录sweep耗时
_intra_sweep_estimate.sample(_intra_sweep_timer.seconds());
//重置_inter_sweep_timer计时器
_inter_sweep_timer.reset();
_inter_sweep_timer.start();
//更新GC时间
jlong now = os::javaTimeNanos() / NANOSECS_PER_MILLISEC;
update_time_of_last_gc(now);
assert(_collectorState == Resizing, "Change of collector state to"
" Resizing must be done under the freelistLocks (plural)");
GenCollectedHeap* gch = GenCollectedHeap::heap();
//清除incremental_collection_failed标识
gch->clear_incremental_collection_failed(); // Worth retrying as fresh space may have been freed up
//更新属性_full_collections_completed
gch->update_full_collections_completed(_collection_count_start);
}
void increment_sweep_count() { _sweep_count++; }
void update_time_of_last_gc(jlong now) {
_time_of_last_gc = now;
}
unsigned int GenCollectedHeap::update_full_collections_completed(unsigned int count) {
MonitorLockerEx ml(FullGCCount_lock, Mutex::_no_safepoint_check_flag);
assert((_full_collections_completed <= _total_full_collections) &&
(count <= _total_full_collections),
"Can't complete more collections than were started");
if (count > _full_collections_completed) {
_full_collections_completed = count;
ml.notify_all();
}
return _full_collections_completed;
}
void Universe::update_heap_info_at_gc() {
_heap_capacity_at_last_gc = heap()->capacity();
_heap_used_at_last_gc = heap()->used();
}
void CMSCollector::sweepWork(ConcurrentMarkSweepGeneration* gen,
bool asynch) {
//校验CMS Token和相关锁都获取了
assert(have_cms_token(), "Should hold cms token");
assert( (asynch && ConcurrentMarkSweepThread::cms_thread_has_cms_token())
|| (!asynch && ConcurrentMarkSweepThread::vm_thread_has_cms_token()),
"Should possess CMS token to sweep");
assert_lock_strong(gen->freelistLock());
assert_lock_strong(bitMapLock());
//校验计时器的状态
assert(!_inter_sweep_timer.is_active(), "Was switched off in an outer context");
assert(_intra_sweep_timer.is_active(), "Was switched on in an outer context");
//更新cmsSpace 空间内存块合并相关计数器
gen->cmsSpace()->beginSweepFLCensus((float)(_inter_sweep_timer.seconds()),
_inter_sweep_estimate.padded_average(),
_intra_sweep_estimate.padded_average());
gen->setNearLargestChunk();
{
SweepClosure sweepClosure(this, gen, &_markBitMap,
CMSYield && asynch);
gen->cmsSpace()->blk_iterate_careful(&sweepClosure);
}
gen->cmsSpace()->sweep_completed();
//更新cmsSpace 空间内存块合并相关计数器
gen->cmsSpace()->endSweepFLCensus(sweep_count());
if (should_unload_classes()) { // unloaded classes this cycle,
//重置计数器
_concurrent_cycles_since_last_unload = 0; // ... reset count
} else { // did not unload classes,
_concurrent_cycles_since_last_unload++; // ... increment count
}
}
void ConcurrentMarkSweepGeneration::setNearLargestChunk() {
//FLSLargestBlockCoalesceProximity的默认值是0.99
double nearLargestPercent = FLSLargestBlockCoalesceProximity;
HeapWord* minAddr = _cmsSpace->bottom();
//找到最大的一个空闲内存块
HeapWord* largestAddr =
(HeapWord*) _cmsSpace->dictionary()->find_largest_dict();
if (largestAddr == NULL) {
//如果dictionary为空
largestAddr = _cmsSpace->end();
}
size_t largestOffset = pointer_delta(largestAddr, minAddr);
size_t nearLargestOffset =
(size_t)((double)largestOffset * nearLargestPercent) - MinChunkSize;
if (PrintFLSStatistics != 0) {
gclog_or_tty->print_cr(
"CMS: Large Block: " PTR_FORMAT ";"
" Proximity: " PTR_FORMAT " -> " PTR_FORMAT,
largestAddr,
_cmsSpace->nearLargestChunk(), minAddr + nearLargestOffset);
}
//设置属性_nearLargestChunk
_cmsSpace->set_nearLargestChunk(minAddr + nearLargestOffset);
}
void set_nearLargestChunk(HeapWord* v) { _nearLargestChunk = v; }
CompactibleFreeListSpace::sweep_completed() {
refillLinearAllocBlocksIfNeeded();
}
size_t sweep_count() const { return _sweep_count; }
9、SweepClosure
SweepClosure包含的属性如下:
- CMSCollector* _collector; // 关联的CMSCollector
- ConcurrentMarkSweepGeneration* _g; //清理的Generation对象
- CompactibleFreeListSpace* _sp; // 清理的Space对象
- HeapWord* _limit;// 执行清理的结束地址
- Mutex* _freelistLock; // CompactibleFreeListSpace的全局锁
- CMSBitMap* _bitMap; // 标记对象存活的BitMap
- bool _inFreeRange; // 是否缓存有待处理的Chunk
- bool _freeRangeInFreeLists; //待处理的Chunk是否是free的
- bool _lastFreeRangeCoalesced; //上一次处理Chunk时是否发生了合并
- bool _yield; //是否需要执行yeild
- HeapWord* _freeFinger; //待处理的Chunk的起始地址
- size_t _freeRangeSize; //待处理的Chunk的大小
重点关注以下方法的实现:
9.1、do_blk_careful
do_blk_careful就是SweepClosure执行清理的核心方法了,调用方CompactibleFreeListSpace::blk_iterate_careful,从bottom地址开始遍历,将bottom地址作为参数给do_blk_careful方法,do_blk_careful方法返回已经处理的内存大小,然后将bottom地址加上size,计算下一个需要遍历的地址,如此循环直到遍历到end地址为止,其实现如下:
SweepClosure::SweepClosure(CMSCollector* collector,
ConcurrentMarkSweepGeneration* g,
CMSBitMap* bitMap, bool should_yield) :
_collector(collector),
_g(g),
_sp(g->cmsSpace()),
_limit(_sp->sweep_limit()),
_freelistLock(_sp->freelistLock()),
_bitMap(bitMap),
_yield(should_yield),
_inFreeRange(false), // No free range at beginning of sweep
_freeRangeInFreeLists(false), // No free range at beginning of sweep
_lastFreeRangeCoalesced(false),
_freeFinger(g->used_region().start())
{
assert(_limit >= _sp->bottom() && _limit <= _sp->end(),
"sweep _limit out of bounds");
if (CMSTraceSweeper) {
gclog_or_tty->print_cr("\n====================\nStarting new sweep with limit " PTR_FORMAT,
_limit);
}
}
size_t SweepClosure::do_blk_careful(HeapWord* addr) {
FreeChunk* fc = (FreeChunk*)addr;
size_t res;
if (addr >= _limit) { //大于或者等于limit说明已经清理完成
assert(_limit >= _sp->bottom() && _limit <= _sp->end(),
"sweep _limit out of bounds");
assert(addr < _sp->end(), "addr out of bounds");
if (inFreeRange()) {
assert(freeFinger() >= _sp->bottom() && freeFinger() < _limit,
err_msg("freeFinger() " PTR_FORMAT " is out-of-bounds", freeFinger()));
flush_cur_free_chunk(freeFinger(),
pointer_delta(addr, freeFinger()));
if (CMSTraceSweeper) {
gclog_or_tty->print("Sweep: last chunk: ");
gclog_or_tty->print("put_free_blk 0x%x (" SIZE_FORMAT ") "
"[coalesced:" SIZE_FORMAT "]\n",
freeFinger(), pointer_delta(addr, freeFinger()),
lastFreeRangeCoalesced());
}
}
//返回addr到end之间的大小,从而终止遍历
return pointer_delta(_sp->end(), addr);
}
assert(addr < _limit, "sweep invariant");
//检查是否需要yield,inFreeRange是否为true
do_yield_check(addr);
if (fc->is_free()) {
//如果addr对应的Chunk本身就是空闲的
res = fc->size();
do_already_free_chunk(fc);
assert(res == fc->size() || ((HeapWord*)fc) + res >= _limit,
"Otherwise the size info doesn't change at this step");
} else if (!_bitMap->isMarked(addr)) {
//如果addr在BitMap中未打标
res = do_garbage_chunk(fc);
} else {
//如果addr在BitMap中已打标
res = do_live_chunk(fc);
}
return res;
}
bool inFreeRange() const { return _inFreeRange; }
HeapWord* freeFinger() const { return _freeFinger; }
void SweepClosure::flush_cur_free_chunk(HeapWord* chunk, size_t size) {
assert(inFreeRange(), "Should only be called if currently in a free range.");
assert(size > 0,
"A zero sized chunk cannot be added to the free lists.");
//如果freeRangeInFreeLists为false
if (!freeRangeInFreeLists()) {
//CMSTestInFreeList表示默认为false
if (CMSTestInFreeList) {
FreeChunk* fc = (FreeChunk*) chunk;
fc->set_size(size);
assert(!_sp->verify_chunk_in_free_list(fc),
"chunk should not be in free lists yet");
}
if (CMSTraceSweeper) {
gclog_or_tty->print_cr(" -- add free block 0x%x (%d) to free lists",
chunk, size);
}
if (lastFreeRangeCoalesced()) {
//记录因为合并增加的内存块的大小
_sp->coalBirth(size);
}
//将其归还到FreeList或者Dictionary
_sp->addChunkAndRepairOffsetTable(chunk, size,
lastFreeRangeCoalesced());
} else if (CMSTraceSweeper) {
gclog_or_tty->print_cr("Already in free list: nothing to flush");
}
set_inFreeRange(false);
set_freeRangeInFreeLists(false);
}
bool freeRangeInFreeLists() const { return _freeRangeInFreeLists; }
bool lastFreeRangeCoalesced() const { return _lastFreeRangeCoalesced; }
inline void SweepClosure::do_yield_check(HeapWord* addr) {
if (ConcurrentMarkSweepThread::should_yield() &&
!_collector->foregroundGCIsActive() &&
_yield) {
do_yield_work(addr);
}
}
void SweepClosure::do_yield_work(HeapWord* addr) {
if (inFreeRange()) {
flush_cur_free_chunk(freeFinger(), pointer_delta(addr, freeFinger()));
}
assert_lock_strong(_bitMap->lock());
assert_lock_strong(_freelistLock);
assert(ConcurrentMarkSweepThread::cms_thread_has_cms_token(),
"CMS thread should hold CMS token");
_bitMap->lock()->unlock();
_freelistLock->unlock();
ConcurrentMarkSweepThread::desynchronize(true);
ConcurrentMarkSweepThread::acknowledge_yield_request();
_collector->stopTimer();
GCPauseTimer p(_collector->size_policy()->concurrent_timer_ptr());
if (PrintCMSStatistics != 0) {
_collector->incrementYields();
}
_collector->icms_wait();
// See the comment in coordinator_yield()
for (unsigned i = 0; i < CMSYieldSleepCount &&
ConcurrentMarkSweepThread::should_yield() &&
!CMSCollector::foregroundGCIsActive(); ++i) {
os::sleep(Thread::current(), 1, false);
ConcurrentMarkSweepThread::acknowledge_yield_request();
}
ConcurrentMarkSweepThread::synchronize(true);
_freelistLock->lock();
_bitMap->lock()->lock_without_safepoint_check();
_collector->startTimer();
}
9.2、do_already_free_chunk
用于处理还是free的FreeChunk,还是free说明该Chunk还在FreeList或者Dictionary中,其核心处理逻辑是do_post_free_or_garbage_chunk,该方法会根据合并策略判断是否跟上一个待处理的内存块合并,如果不合并则将上一个待处理的内存块归还到FreeList或者Dictionary中,当前处理的Chunk初始化成新的待处理内存块。
void SweepClosure::do_already_free_chunk(FreeChunk* fc) {
const size_t size = fc->size();
//CMSTestInFreeList默认为false
if (CMSTestInFreeList && !fc->cantCoalesce()) {
assert(_sp->verify_chunk_in_free_list(fc),
"free chunk should be in free lists");
}
//校验fc对应的内存区域在BitMap中未打标
HeapWord* const addr = (HeapWord*) fc;
assert(!_bitMap->isMarked(addr), "free chunk should be unmarked");
_bitMap->verifyNoOneBitsInRange(addr + 1, addr + size);
if (!fc->cantCoalesce()) {
//cantCoalesce为false,即这个Chunk可以合并
if (_sp->adaptive_freelists()) {
//如果使用adaptive_freelists,默认配置下,该属性为true
//将该Chunk合并到另外一个Chunk或者归还
do_post_free_or_garbage_chunk(fc, size);
} else { // Not adaptive free lists
if (!inFreeRange()) {
FreeChunk* nextChunk = (FreeChunk*)(addr + size);
assert((HeapWord*)nextChunk <= _sp->end(), "Chunk size out of bounds?");
if ((HeapWord*)nextChunk < _sp->end() && // There is another free chunk to the right ...
nextChunk->is_free() && // ... which is free...
nextChunk->cantCoalesce()) { // ... but can't be coalesced
// nothing to do
} else {
initialize_free_range(addr, true);
}
} else {
// the midst of a free range, we are coalescing
print_free_block_coalesced(fc);
if (CMSTraceSweeper) {
gclog_or_tty->print(" -- pick up free block 0x%x (%d)\n", fc, size);
}
// remove it from the free lists
_sp->removeFreeChunkFromFreeLists(fc);
if (freeRangeInFreeLists()) {
FreeChunk* ffc = (FreeChunk*) freeFinger();
assert(ffc->size() == pointer_delta(addr, freeFinger()),
"Size of free range is inconsistent with chunk size.");
if (CMSTestInFreeList) {
assert(_sp->verify_chunk_in_free_list(ffc),
"free range is not in free lists");
}
_sp->removeFreeChunkFromFreeLists(ffc);
set_freeRangeInFreeLists(false);
}
}
}
if (inFreeRange()) lookahead_and_flush(fc, size);
} else {
//cantCoalesce返true,即该chunk不能合并处理
if (inFreeRange()) {
// we kicked some butt; time to pick up the garbage
assert(freeFinger() < addr, "freeFinger points too high");
flush_cur_free_chunk(freeFinger(), pointer_delta(addr, freeFinger()));
}
//该Chunk是空闲的,且不能合并则不做任何处理,继续留在FreeList或者Dictionary中
}
}
//注意调用此方法时fc有可能是空闲的,也可能是非空闲的
void SweepClosure::do_post_free_or_garbage_chunk(FreeChunk* fc,
size_t chunkSize) {
//注意该方法只在_sp->adaptive_freelists()方法返回true的时候调用
const bool fcInFreeLists = fc->is_free();
assert(_sp->adaptive_freelists(), "Should only be used in this case.");
assert((HeapWord*)fc <= _limit, "sweep invariant");
//CMSTestInFreeList配置默认为true
if (CMSTestInFreeList && fcInFreeLists) {
assert(_sp->verify_chunk_in_free_list(fc), "free chunk is not in free lists");
}
if (CMSTraceSweeper) {
gclog_or_tty->print_cr(" -- pick up another chunk at 0x%x (%d)", fc, chunkSize);
}
HeapWord* const fc_addr = (HeapWord*) fc;
bool coalesce = false;
//freeFinger初始值为used_region().start()
const size_t left = pointer_delta(fc_addr, freeFinger());
const size_t right = chunkSize;
//FLSCoalescePolicy的默认值是2,根据不同的策略判断是否需要合并
switch (FLSCoalescePolicy) {
// numeric value forms a coalition aggressiveness metric
case 0: { // never coalesce
coalesce = false;
break;
}
case 1: { // coalesce if left & right chunks on overpopulated lists
coalesce = _sp->coalOverPopulated(left) &&
_sp->coalOverPopulated(right);
break;
}
case 2: { // coalesce if left chunk on overpopulated list (default)
coalesce = _sp->coalOverPopulated(left);
break;
}
case 3: { // coalesce if left OR right chunk on overpopulated list
coalesce = _sp->coalOverPopulated(left) ||
_sp->coalOverPopulated(right);
break;
}
case 4: { // always coalesce
coalesce = true;
break;
}
default:
ShouldNotReachHere();
}
//inFreeRange表明有一个待处理的Chunk
const bool doCoalesce = inFreeRange()
&& (coalesce || _g->isNearLargestChunk(fc_addr));
if (doCoalesce) {
//需要执行合并
//freeRangeInFreeLists为true,表示待处理的Chunk也是Free的
if (freeRangeInFreeLists()) {
FreeChunk* const ffc = (FreeChunk*)freeFinger();
//校验fc_addr挨着待处理的Chunk的后面
assert(ffc->size() == pointer_delta(fc_addr, freeFinger()),
"Size of free range is inconsistent with chunk size.");
if (CMSTestInFreeList) {
assert(_sp->verify_chunk_in_free_list(ffc),
"Chunk is not in free lists");
}
_sp->coalDeath(ffc->size());
//将ffc从FreeList或者Dictionary中移除
//如果freeRangeInFreeLists为false,说明待处理的Chunk是一个需要被回收掉的垃圾对象,该Chunk已经从FreeList或者Dictionary中移除了
_sp->removeFreeChunkFromFreeLists(ffc);
//将freeRangeInFreeLists置为false,保证其在flush_cur_free_chunk时可以合并
set_freeRangeInFreeLists(false);
}
//fcInFreeLists为true表示当前处理的这个Chunk也是空闲的
if (fcInFreeLists) {
_sp->coalDeath(chunkSize);
assert(fc->size() == chunkSize,
"The chunk has the wrong size or is not in the free lists");
//将fc从FreeList或者Dictionary中移除
//同上fcInFreeLists为false,说明当前处理的Chunk是一个需要被回收掉的垃圾对象,该Chunk已经从FreeList或者Dictionary中移除了
_sp->removeFreeChunkFromFreeLists(fc);
}
//设置lastFreeRangeCoalesced为true,表示上一个Chunk发生了合并
//注意此时freeFinger的地址并未改变,下一次flush_cur_free_chunk时就会将该freeFinger到当前遍历的起始地址之间的内存块归还到FreeList或者Dictionary中,从而实现合并的效果
set_lastFreeRangeCoalesced(true);
print_free_block_coalesced(fc);
} else { //inFreeRange为false或者coalesce为false
if (inFreeRange()) {
//如果inFreeRange为true,那coalesce为false,则将freeFinger对应的空闲内存块归还
flush_cur_free_chunk(freeFinger(),
pointer_delta(fc_addr, freeFinger()));
}
//将当前处理的Chunk临时保存起来
initialize_free_range((HeapWord*)fc, fcInFreeLists);
}
}
bool CompactibleFreeListSpace::coalOverPopulated(size_t size) {
if (size < SmallForDictionary) {
AdaptiveFreeList<FreeChunk> *fl = &_indexedFreeList[size];
return (fl->coal_desired() < 0) ||
((int)fl->count() > fl->coal_desired());
} else {
return dictionary()->coal_dict_over_populated(size);
}
}
bool ConcurrentMarkSweepGeneration::isNearLargestChunk(HeapWord* addr) {
return addr >= _cmsSpace->nearLargestChunk();
}
void SweepClosure::initialize_free_range(HeapWord* freeFinger,
bool freeRangeInFreeLists) {
if (CMSTraceSweeper) {
gclog_or_tty->print("---- Start free range at 0x%x with free block (%d)\n",
freeFinger, freeRangeInFreeLists);
}
//校验inFreeRange为false
assert(!inFreeRange(), "Trampling existing free range");
//将inFreeRange重置为true
set_inFreeRange(true);
//lastFreeRangeCoalesced恢复成默认的false
set_lastFreeRangeCoalesced(false);
//设置freeFinger
set_freeFinger(freeFinger);
//freeRangeInFreeLists就是该Chunk是否是free的
set_freeRangeInFreeLists(freeRangeInFreeLists);
if (CMSTestInFreeList) {
if (freeRangeInFreeLists) {
FreeChunk* fc = (FreeChunk*) freeFinger;
assert(fc->is_free(), "A chunk on the free list should be free.");
assert(fc->size() > 0, "Free range should have a size");
assert(_sp->verify_chunk_in_free_list(fc), "Chunk is not in free lists");
}
}
}
9.3 、do_garbage_chunk
该方法用于处理需要被回收的垃圾对象,其核心实现同样是do_post_free_or_garbage_chunk,在此之外多了一步lookahead_and_flush方法,该方法会判断当前处理的内存块是否跨过了sweep_limit,如果跨过了则将待处理的内存块归还,从而终止sweep遍历。
size_t SweepClosure::do_garbage_chunk(FreeChunk* fc) {
//fc是一个需要回收掉的Chunk,将其归还或者合并成一个更大的Chunk
HeapWord* const addr = (HeapWord*) fc;
//获取该对象的大小
const size_t size = CompactibleFreeListSpace::adjustObjectSize(oop(addr)->size());
if (_sp->adaptive_freelists()) {
//如果使用adaptive_freelists,默认配置下返回true
//校验该对应对应的内存区域都没有打标
_bitMap->verifyNoOneBitsInRange(addr + 1, addr + size);
//将其归还或者合并
do_post_free_or_garbage_chunk(fc, size);
} else {
if (!inFreeRange()) {
assert(size > 0, "A free range should have a size");
initialize_free_range(addr, false);
} else {
if (CMSTraceSweeper) {
gclog_or_tty->print(" -- pick up garbage 0x%x (%d) \n", fc, size);
}
if (freeRangeInFreeLists()) {
FreeChunk* ffc = (FreeChunk*)freeFinger();
assert(ffc->size() == pointer_delta(addr, freeFinger()),
"Size of free range is inconsistent with chunk size.");
if (CMSTestInFreeList) {
assert(_sp->verify_chunk_in_free_list(ffc),
"free range is not in free lists");
}
_sp->removeFreeChunkFromFreeLists(ffc);
set_freeRangeInFreeLists(false);
}
set_lastFreeRangeCoalesced(true);
}
_bitMap->verifyNoOneBitsInRange(addr + 1, addr + size);
}
assert(_limit >= addr + size,
"A freshly garbage chunk can't possibly straddle over _limit");
if (inFreeRange()) lookahead_and_flush(fc, size);
return size;
}
void SweepClosure::lookahead_and_flush(FreeChunk* fc, size_t chunk_size) {
//do_post_free_or_garbage_chunk方法保证inFreeRange为true
assert(inFreeRange(), "Should only be called if currently in a free range.");
//获取结束地址
HeapWord* const eob = ((HeapWord*)fc) + chunk_size;
assert(_sp->used_region().contains(eob - 1),
err_msg("eob = " PTR_FORMAT " eob-1 = " PTR_FORMAT " _limit = " PTR_FORMAT
" out of bounds wrt _sp = [" PTR_FORMAT "," PTR_FORMAT ")"
" when examining fc = " PTR_FORMAT "(" SIZE_FORMAT ")",
eob, eob-1, _limit, _sp->bottom(), _sp->end(), fc, chunk_size));
if (eob >= _limit) {
//要么eob刚好等于limit,此时fc是一个对象,要么eob是一个空闲内存块
assert(eob == _limit || fc->is_free(), "Only a free chunk should allow us to cross over the limit");
if (CMSTraceSweeper) {
gclog_or_tty->print_cr("_limit " PTR_FORMAT " reached or crossed by block "
"[" PTR_FORMAT "," PTR_FORMAT ") in space "
"[" PTR_FORMAT "," PTR_FORMAT ")",
_limit, fc, eob, _sp->bottom(), _sp->end());
}
// Return the storage we are tracking back into the free lists.
if (CMSTraceSweeper) {
gclog_or_tty->print_cr("Flushing ... ");
}
assert(freeFinger() < eob, "Error");
//将上一个待处理的Chunk归还
flush_cur_free_chunk( freeFinger(), pointer_delta(eob, freeFinger()));
}
}
9.4、do_live_chunk
该方法用于处理已经被标记的对象,如果对象已初始化则根据Klass直接获取对象大小,如果未初始化则根据被打标的对象结束地址获取对象大小。
size_t SweepClosure::do_live_chunk(FreeChunk* fc) {
HeapWord* addr = (HeapWord*) fc;
if (inFreeRange()) {
//如果有待处理的Chunk
assert(freeFinger() < addr, "freeFinger points too high");
//将该Chunk归还到FreeList或者Dictionary中,注意归还的Chunk的大小是addr到freeFinger之间的大小
//freeFinger是待处理的Chunk的起始地址,如果有新的Chunk跟该Chunk合并,freeFinger的地址不变
flush_cur_free_chunk(freeFinger(), pointer_delta(addr, freeFinger()));
}
size_t size;
assert(_bitMap->isMarked(addr), "Tautology for this control point");
if (_bitMap->isMarked(addr + 1)) {
//如果该对象未初始化,则查找下一个打标地址,该地址就是对象的结束地址,据此计算对象大小
HeapWord* nextOneAddr = _bitMap->getNextMarkedWordAddress(addr + 2);
size = pointer_delta(nextOneAddr + 1, addr);
assert(size == CompactibleFreeListSpace::adjustObjectSize(size),
"alignment problem");
} else {
//该对象已经完成初始化
assert(oop(addr)->klass_or_null() != NULL,
"Should be an initialized object");
assert(oop(addr)->is_oop(true), "live block should be an oop");
//获取该对象的大小
size = CompactibleFreeListSpace::adjustObjectSize(oop(addr)->size());
assert(size >= 3, "Necessary for Printezis marks to work");
assert(!_bitMap->isMarked(addr+1), "Tautology for this control point");
}
return size;
}
10、Sweeping步骤 总结
Sweeping步骤不要求JVM处于安全点,但是必须获取CMS Token,操作BitMap的BitMapLock,操作cmsSpace的freeListLock锁,整体逻辑比较简单,就是遍历老年代的bottom到sweep_limit的内存区域,sweep_limit是在前面的步骤中保存的,先将bottom地址给SweepClosure::do_blk_careful方法,该方法会判断该地址对应的内存块是否空闲,是否垃圾对象,是否存活对象,如果是空闲内存块和垃圾对象则会通过指定的策略判断是否需要合并成一个大的内存块,并将合并后的大内存块归还到cmsSpace中,处理完成返回已处理的内存块的大小,然后根据bottom地址加上该内存块的大小得到下一个需要处理的地址,如此循环直到遍历的地址大于或者等于sweep_limit。