目录
6、VM_CMS_Initial_Mark / VM_CMS_Final_Remark
根据上一篇《Hotspot 垃圾回收之ConcurrentMarkSweepGeneration(三) 源码解析》对ConcurrentMarkSweepGeneration主要方法的实现分析可知,老年代的垃圾回收相关细节被完全封装在CMSCollector中,调用入口就是ConcurrentMarkSweepThread调用的CMSCollector::collect_in_background和ConcurrentMarkSweepGeneration调用的CMSCollector::collect方法,从本篇开始就顺着这两个入口的对相关方法的调用顺序,逐步讲解CMSCollector的实现细节,其定义和构造方法已经在《Hotspot 垃圾回收之ConcurrentMarkSweepGeneration(一) 源码解析》中讲解过了,重点关注相关方法的实现。
1、acquire_control_and_collect
acquire_control_and_collect就是CMSCollector::collect方法的核心实现了,首先会从执行后台GC的CMSThread中获取GC的执行权限,然后判断是否需要压缩老年代,根据是否压缩走不同的标记清理逻辑。其实现如下:
void CMSCollector::acquire_control_and_collect(bool full,
bool clear_all_soft_refs) {
//当前线程处于安全点上
assert(SafepointSynchronize::is_at_safepoint(), "should be at safepoint");
//当前线程是VMThread
assert(!Thread::current()->is_ConcurrentGC_thread(),
"shouldn't try to acquire control from self!");
//校验VMThread已经获取了CMS Token
assert(ConcurrentMarkSweepThread::vm_thread_has_cms_token(),
"VM thread should have CMS token");
//当前的垃圾回收状态
CollectorState first_state = _collectorState;
//_foregroundGCIsActive置为true表示前台GC已经激活了
_foregroundGCIsActive = true;
//临时暂停ICMS模式
ICMSDisabler icms_disabler;
//校验已经获取了锁
assert_lock_strong(bitMapLock());
assert(haveFreelistLocks(), "Must be holding free list locks");
//释放锁等待后台GC让出GC执行权
bitMapLock()->unlock();
releaseFreelistLocks();
{
//获取锁CGC_lock
MutexLockerEx x(CGC_lock, Mutex::_no_safepoint_check_flag);
if (_foregroundGCShouldWait) {
//_foregroundGCShouldWait为true,表示后台GC正在进行
assert(ConcurrentMarkSweepThread::cmst() != NULL,
"CMS thread must be running");
//释放VMThread占用的CMS Token
ConcurrentMarkSweepThread::clear_CMS_flag(
ConcurrentMarkSweepThread::CMS_vm_has_token); // release token
// 唤醒可能等待的CMS Thread继续执行
CGC_lock->notify();
assert(!ConcurrentMarkSweepThread::vm_thread_wants_cms_token(),
"Possible deadlock");
while (_foregroundGCShouldWait) {
//循环等待直到_foregroundGCShouldWait变为false,即后台GC交出了GC执行权
CGC_lock->wait(Mutex::_no_safepoint_check_flag);
}
//重新获取CMS Token
ConcurrentMarkSweepThread::set_CMS_flag(
ConcurrentMarkSweepThread::CMS_vm_has_token);
}
}
assert(ConcurrentMarkSweepThread::vm_thread_has_cms_token(),
"VM thread should have CMS token");
//重新获取锁
getFreelistLocks();
bitMapLock()->lock_without_safepoint_check();
if (TraceCMSState) {
gclog_or_tty->print_cr("CMS foreground collector has asked for control "
INTPTR_FORMAT " with first state %d", Thread::current(), first_state);
gclog_or_tty->print_cr(" gets control with state %d", _collectorState);
}
//判断是否需要进行压缩,如果不需要是否需要标记清理
bool should_compact = false;
bool should_start_over = false;
decide_foreground_collection_type(clear_all_soft_refs,
&should_compact, &should_start_over);
if (first_state > Idling) {
//如果当前GC状态不是空闲,则说明后台GC已经完成了部分GC步骤,打印被中断日志
report_concurrent_mode_interruption();
}
set_did_compact(should_compact);
if (should_compact) {
//清空discovered References链表中的References实例,Mark-Sweep-Compact代码假定他们的referent都不是NULL且
//References实例都是存活的
ref_processor()->clean_up_discovered_references();
if (first_state > Idling) {
//保存当前堆内存和元空间的使用情况
save_heap_summary();
}
//执行压缩并标记清理,底层核心实现是GenMarkSweep
do_compaction_work(clear_all_soft_refs);
DefNewGeneration* young_gen = _young_gen->as_DefNewGeneration();
//获取eden区的最大容量
size_t max_eden_size = young_gen->max_capacity() -
young_gen->to()->capacity() -
young_gen->from()->capacity();
GenCollectedHeap* gch = GenCollectedHeap::heap();
GCCause::Cause gc_cause = gch->gc_cause();
size_policy()->check_gc_overhead_limit(_young_gen->used(),
young_gen->eden()->used(),
_cmsGen->max_capacity(),
max_eden_size,
full,
gc_cause,
gch->collector_policy());
} else {
//执行标记清理
do_mark_sweep_work(clear_all_soft_refs, first_state,
should_start_over);
}
//清空扩展的原因
clear_expansion_cause();
//_foregroundGCIsActive置为false
_foregroundGCIsActive = false;
return;
}
void CMSCollector::decide_foreground_collection_type(
bool clear_all_soft_refs, bool* should_compact,
bool* should_start_over) {
GenCollectedHeap* gch = GenCollectedHeap::heap();
assert(gch->collector_policy()->is_two_generation_policy(),
"You may want to check the correctness of the following");
if (gch->incremental_collection_will_fail(false /* don't consult_young */)) {
//如果增量收集会失败
assert(!_cmsGen->incremental_collection_failed(),
"Should have been noticed, reacted to and cleared");
_cmsGen->set_incremental_collection_failed();
}
//UseCMSCompactAtFullCollection表示在Full GC时是否执行压缩,默认为true
//CMSFullGCsBeforeCompaction表示一个阈值,Full GC的次数超过该值才会执行压缩
*should_compact =
UseCMSCompactAtFullCollection &&
((_full_gcs_since_conc_gc >= CMSFullGCsBeforeCompaction) ||
GCCause::is_user_requested_gc(gch->gc_cause()) || //用户通过System.gc方法请求GC
gch->incremental_collection_will_fail(true /* consult_young */)); //增量收集失败
*should_start_over = false;
//如果should_compact为false且clear_all_soft_refs为true
if (clear_all_soft_refs && !*should_compact) {
//当clear_all_soft_refs为true时是否需要压缩,默认为true
if (CMSCompactWhenClearAllSoftRefs) {
*should_compact = true;
} else {
//如果当前GC已经过FinalMarking环节了,在该环节才处理所有的Refenrence,则需要重新开始一轮GC,
//重新查找待处理的Refenrence
if (_collectorState > FinalMarking) {
//将GC的状态设置为重置
_collectorState = Resetting; // skip to reset to start new cycle
//执行重置
reset(false /* == !asynch */);
*should_start_over = true;
}
}
}
}
void CMSCollector::report_concurrent_mode_interruption() {
if (is_external_interruption()) {
if (PrintGCDetails) {
gclog_or_tty->print(" (concurrent mode interrupted)");
}
} else {
if (PrintGCDetails) {
gclog_or_tty->print(" (concurrent mode failure)");
}
_gc_tracer_cm->report_concurrent_mode_failure();
}
}
bool CMSCollector::is_external_interruption() {
GCCause::Cause cause = GenCollectedHeap::heap()->gc_cause();
return GCCause::is_user_requested_gc(cause) ||
GCCause::is_serviceability_requested_gc(cause);
}
inline static bool is_user_requested_gc(GCCause::Cause cause) {
return (cause == GCCause::_java_lang_system_gc ||
cause == GCCause::_jvmti_force_gc);
}
inline static bool is_serviceability_requested_gc(GCCause::Cause
cause) {
return (cause == GCCause::_jvmti_force_gc ||
cause == GCCause::_heap_inspection ||
cause == GCCause::_heap_dump);
}
void CMSCollector::save_heap_summary() {
GenCollectedHeap* gch = GenCollectedHeap::heap();
_last_heap_summary = gch->create_heap_summary();
_last_metaspace_summary = gch->create_metaspace_summary();
}
其调用链如下:
代码中用到的ICMSDisabler的定义如下:
2、do_compaction_work
该方法是老年代需要压缩时执行msc_collection即Mark-Sweep-Compact collection的入口方法,核心逻辑都在GenMarkSweep::invoke_at_safepoint方法中,该方法就负责msc_collection开始前的通知和准备,结束后通知和状态重置工作,其实现如下:
void CMSCollector::do_compaction_work(bool clear_all_soft_refs) {
GenCollectedHeap* gch = GenCollectedHeap::heap();
//通知计时器和跟踪器 GC开始
STWGCTimer* gc_timer = GenMarkSweep::gc_timer();
gc_timer->register_gc_start();
SerialOldTracer* gc_tracer = GenMarkSweep::gc_tracer();
gc_tracer->report_gc_start(gch->gc_cause(), gc_timer->gc_start());
GCTraceTime t("CMS:MSC ", PrintGCDetails && Verbose, true, NULL, gc_tracer->gc_id());
if (PrintGC && Verbose && !(GCCause::is_user_requested_gc(gch->gc_cause()))) {
gclog_or_tty->print_cr("Compact ConcurrentMarkSweepGeneration after %d "
"collections passed to foreground collector", _full_gcs_since_conc_gc);
}
if (UseAdaptiveSizePolicy) {
//msc就是Mark-Sweep-Compact的简写,通知CMSAdaptiveSizePolicy GC开始
size_policy()->msc_col