目錄
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_collection_begin();
}
MemRegion new_span(GenCollectedHeap::heap()->reserved_region());
//暫時修改ref_processor的span屬性爲new_span
ReferenceProcessorSpanMutator rp_mut_span(ref_processor(), new_span);
//暫時修改ref_processor的is_alive_non_header屬性爲NULL
ReferenceProcessorIsAliveMutator rp_mut_closure(ref_processor(), NULL);
//暫時修改 _processing_is_mt屬性爲false
ReferenceProcessorMTProcMutator rp_mut_mt_processing(ref_processor(), false);
//暫時修改discovery_is_atomic屬性爲true
ReferenceProcessorAtomicMutator rp_mut_atomic(ref_processor(), true);
//暫時修改 discovery_is_mt屬性爲false
ReferenceProcessorMTDiscoveryMutator rp_mut_discovery(ref_processor(), false);
ref_processor()->set_enqueuing_is_done(false);
//允許Reference實例查找
ref_processor()->enable_discovery(false /*verify_disabled*/, false /*check_no_refs*/);
//設置清除策略
ref_processor()->setup_policy(clear_all_soft_refs);
assert(_collectorState != Idling || _modUnionTable.isAllClear(),
"_modUnionTable should be clear if the baton was not passed");
//清空_modUnionTable中的標記
_modUnionTable.clear_all();
assert(_collectorState != Idling || _ct->klass_rem_set()->mod_union_is_clear(),
"mod union for klasses should be clear if the baton was passed");
//遍歷Klass清理_accumulated_modified_oops標識
_ct->klass_rem_set()->clear_mod_union();
//沒開始GC,所以_intra_sweep_timer不是激活的,此時_inter_sweep_timer應該是激活的
assert(!_intra_sweep_timer.is_active(), "_intra_sweep_timer should be inactive");
if (_inter_sweep_timer.is_active()) {
//停止計時
_inter_sweep_timer.stop();
//重置cmsSpace內存塊合併相關的計數器
_cmsGen->cmsSpace()->beginSweepFLCensus((float)(_inter_sweep_timer.seconds()),
_inter_sweep_estimate.padded_average(),
_intra_sweep_estimate.padded_average());
}
//執行壓縮,標記清理等垃圾回收步驟
GenMarkSweep::invoke_at_safepoint(_cmsGen->level(),
ref_processor(), clear_all_soft_refs);
//重置_collectorState和CMSCollector
_collectorState = Resetting;
assert(_restart_addr == NULL,
"Should have been NULL'd before baton was passed");
reset(false /* == !asynch */);
//老年代壓縮後的重置
_cmsGen->reset_after_compaction();
_concurrent_cycles_since_last_unload = 0;
//重置PLAB ChunkArray數組
if (_survivor_plab_array != NULL) {
reset_survivor_plab_arrays();
}
//GC結束重置cmsSpace內存塊合併相關的計數器
_cmsGen->cmsSpace()->endSweepFLCensus(sweep_count() /* fake */);
//_inter_sweep_timer重置
_inter_sweep_timer.reset();
_inter_sweep_timer.start();
//通知GC結束
if (UseAdaptiveSizePolicy) {
size_policy()->msc_collection_end(gch->gc_cause());
}
gc_timer->register_gc_end();
gc_tracer->report_gc_end(gc_timer->gc_end(), gc_timer->time_partitions());
//注意此情形下compute_new_size由上層的GenCollectHeap的do_collect方法調用
}
void CMSCollector::reset_survivor_plab_arrays() {
for (uint i = 0; i < ParallelGCThreads; i++) {
_survivor_plab_array[i].reset();
}
}
//通過構造和析構函數臨時修改ReferenceProcessor的span屬性
class ReferenceProcessorSpanMutator: StackObj {
private:
ReferenceProcessor* _rp;
MemRegion _saved_span;
public:
ReferenceProcessorSpanMutator(ReferenceProcessor* rp,
MemRegion span):
_rp(rp) {
_saved_span = _rp->span();
_rp->set_span(span);
}
~ReferenceProcessorSpanMutator() {
_rp->set_span(_saved_span);
}
};
//通過構造和析構函數臨時修改ReferenceProcessor的is_alive_non_header屬性
class ReferenceProcessorIsAliveMutator: StackObj {
private:
ReferenceProcessor* _rp;
BoolObjectClosure* _saved_cl;
public:
ReferenceProcessorIsAliveMutator(ReferenceProcessor* rp,
BoolObjectClosure* cl):
_rp(rp) {
_saved_cl = _rp->is_alive_non_header();
_rp->set_is_alive_non_header(cl);
}
~ReferenceProcessorIsAliveMutator() {
_rp->set_is_alive_non_header(_saved_cl);
}
};
//通過構造和析構函數臨時修改ReferenceProcessor的_processing_is_mt屬性
class ReferenceProcessorMTProcMutator: StackObj {
private:
ReferenceProcessor* _rp;
bool _saved_mt;
public:
ReferenceProcessorMTProcMutator(ReferenceProcessor* rp,
bool mt):
_rp(rp) {
_saved_mt = _rp->processing_is_mt();
_rp->set_mt_processing(mt);
}
~ReferenceProcessorMTProcMutator() {
_rp->set_mt_processing(_saved_mt);
}
};
//通過構造和析構函數臨時修改ReferenceProcessor的discovery_is_atomic屬性
class ReferenceProcessorAtomicMutator: StackObj {
private:
ReferenceProcessor* _rp;
bool _saved_atomic_discovery;
public:
ReferenceProcessorAtomicMutator(ReferenceProcessor* rp,
bool atomic):
_rp(rp) {
_saved_atomic_discovery = _rp->discovery_is_atomic();
_rp->set_atomic_discovery(atomic);
}
~ReferenceProcessorAtomicMutator() {
_rp->set_atomic_discovery(_saved_atomic_discovery);
}
};
//通過構造和析構函數臨時修改ReferenceProcessor的discovery_is_mt屬性
class ReferenceProcessorMTDiscoveryMutator: StackObj {
private:
ReferenceProcessor* _rp;
bool _saved_mt;
public:
ReferenceProcessorMTDiscoveryMutator(ReferenceProcessor* rp,
bool mt):
_rp(rp) {
_saved_mt = _rp->discovery_is_mt();
_rp->set_mt_discovery(mt);
}
~ReferenceProcessorMTDiscoveryMutator() {
_rp->set_mt_discovery(_saved_mt);
}
};
調用鏈如下:
3、do_mark_sweep_work
do_mark_sweep_work是不需要老年代空間壓縮時執行標記清理等垃圾回收動作的入口,核心實現根據GC的步驟放在每個步驟對應的方法中,do_mark_sweep_work負責根據_collectorState狀態值調用對應的步驟方法。其實現如下:
void CMSCollector::do_mark_sweep_work(bool clear_all_soft_refs,
CollectorState first_state, bool should_start_over) {
if (PrintGC && Verbose) {
gclog_or_tty->print_cr("Pass concurrent collection to foreground "
"collector with count %d",
_full_gcs_since_conc_gc);
}
switch (_collectorState) {
case Idling:
//如果first_state是Idling,則表明未開始GC,將狀態流轉成InitialMarking
//如果should_start_over爲true,表示需要重新開始,無論之前是什麼狀態,都流轉成InitialMarking
if (first_state == Idling || should_start_over) {
_collectorState = InitialMarking;
}
break;
case Precleaning:
//如果後臺GC已經執行完了Precleaning步驟,則將狀態流程成FinalMarking
_collectorState = FinalMarking;
}
collect_in_foreground(clear_all_soft_refs, GenCollectedHeap::heap()->gc_cause());
//compute_new_size方法會被上層的do_collection方法調用
}
void CMSCollector::collect_in_foreground(bool clear_all_soft_refs, GCCause::Cause cause) {
//校驗_foregroundGCIsActive爲true,_foregroundGCShouldWait爲false,即當前方法是前臺GC調用的
assert(_foregroundGCIsActive && !_foregroundGCShouldWait,
"Foreground collector should be waiting, not executing");
//校驗當前線程是VMThread
assert(Thread::current()->is_VM_thread(), "A foreground collection"
"may only be done by the VM Thread with the world stopped");
//校驗VMThread獲取了CMS Token
assert(ConcurrentMarkSweepThread::vm_thread_has_cms_token(),
"VM thread should have CMS token");
//生成GC ID
const GCId gc_id = _collectorState == InitialMarking ? GCId::peek() : _gc_tracer_cm->gc_id();
if (UseAdaptiveSizePolicy) {
//通知ms_collection 開始,ms是Mark-Sweep的縮寫
size_policy()->ms_collection_begin();
}
COMPILER2_PRESENT(DerivedPointerTableDeactivate dpt_deact);
HandleMark hm; // Discard invalid handles created during verification
if (VerifyBeforeGC &&
GenCollectedHeap::heap()->total_collections() >= VerifyGCStartAt) {
Universe::verify();
}
//設置回收策略
ref_processor()->setup_policy(clear_all_soft_refs);
//判斷是否需要卸載Class
update_should_unload_classes();
bool init_mark_was_synchronous = false; // until proven otherwise
//通過while循環在不同的狀態間流轉,直到GC結束,狀態變成Idling
while (_collectorState != Idling) {
if (TraceCMSState) {
gclog_or_tty->print_cr("Thread " INTPTR_FORMAT " in CMS state %d",
Thread::current(), _collectorState);
}
switch (_collectorState) {
case InitialMarking:
//通知GC開始
register_foreground_gc_start(cause);
init_mark_was_synchronous = true; // fact to be exploited in re-mark
//檢查老年代以外的對象指向老年代的引用,執行完成將_collectorState置爲Marking
checkpointRootsInitial(false);
assert(_collectorState == Marking, "Collector state should have changed"
" within checkpointRootsInitial()");
break;
case Marking:
if (VerifyDuringGC &&
GenCollectedHeap::heap()->total_collections() >= VerifyGCStartAt) {
Universe::verify("Verify before initial mark: ");
}
{
//從根節點開始標記存活對象
bool res = markFromRoots(false);
assert(res && _collectorState == FinalMarking, "Collector state should "
"have changed");
break;
}
case FinalMarking:
if (VerifyDuringGC &&
GenCollectedHeap::heap()->total_collections() >= VerifyGCStartAt) {
Universe::verify("Verify before re-mark: ");
}
//再次檢查指向老年代對象的引用
checkpointRootsFinal(false, clear_all_soft_refs,
init_mark_was_synchronous);
assert(_collectorState == Sweeping, "Collector state should not "
"have changed within checkpointRootsFinal()");
break;
case Sweeping:
if (VerifyDuringGC &&
GenCollectedHeap::heap()->total_collections() >= VerifyGCStartAt) {
Universe::verify("Verify before sweep: ");
}
//執行清理
sweep(false);
assert(_collectorState == Resizing, "Incorrect state");
break;
case Resizing: {
//調整大小就是執行compute_new_size方法,在其他地方執行,所以此處不做啥
//直接將狀態置爲Resetting
_collectorState = Resetting;
break;
}
case Resetting:
if (VerifyDuringGC &&
GenCollectedHeap::heap()->total_collections() >= VerifyGCStartAt) {
Universe::verify("Verify before reset: ");
}
//保存GC結束後的堆內存和元空間的使用情況
save_heap_summary();
//CMSCollector重置,該方法會通知計時器等GC結束
reset(false);
assert(_collectorState == Idling, "Collector state should "
"have changed");
break;
case Precleaning:
case AbortablePreclean:
// Elide the preclean phase
_collectorState = FinalMarking;
break;
default:
ShouldNotReachHere();
}
if (TraceCMSState) {
gclog_or_tty->print_cr(" Thread " INTPTR_FORMAT " done - next CMS state %d",
Thread::current(), _collectorState);
}
}
if (UseAdaptiveSizePolicy) {
GenCollectedHeap* gch = GenCollectedHeap::heap();
//通知GC結束
size_policy()->ms_collection_end(gch->gc_cause());
}
if (VerifyAfterGC &&
GenCollectedHeap::heap()->total_collections() >= VerifyGCStartAt) {
Universe::verify();
}
if (TraceCMSState) {
gclog_or_tty->print_cr("CMS Thread " INTPTR_FORMAT
" exiting collection CMS state %d",
Thread::current(), _collectorState);
}
}
void CMSCollector::update_should_unload_classes() {
_should_unload_classes = false;
//ExplicitGCInvokesConcurrentAndUnloadsClasses表示通過System.gc方法觸發GC時是否卸載Class,默認爲false
if (_full_gc_requested && ExplicitGCInvokesConcurrentAndUnloadsClasses) {
_should_unload_classes = true;
} else if (CMSClassUnloadingEnabled) { // CMSClassUnloadingEnabled表示CMS GC時是否允許Class卸載
//CMSClassUnloadingMaxInterval表示一個閾值,如果自上一次Class卸載後GC的次數超過該值則執行Class卸載
_should_unload_classes = (concurrent_cycles_since_last_unload() >=
CMSClassUnloadingMaxInterval)
|| _cmsGen->is_too_full();
}
}
unsigned int concurrent_cycles_since_last_unload() const {
return _concurrent_cycles_since_last_unload;
}
void CMSCollector::register_foreground_gc_start(GCCause::Cause cause) {
if (!_cms_start_registered) {
//通知GC開始
register_gc_start(cause);
}
}
void CMSCollector::register_gc_start(GCCause::Cause cause) {
_cms_start_registered = true;
_gc_timer_cm->register_gc_start();
_gc_tracer_cm->report_gc_start(cause, _gc_timer_cm->gc_start());
}
其調用如下:
4、collect_in_background
collect_in_background用於CMSThread觸發的後臺垃圾回收,其實現如下:
void CMSCollector::collect_in_background(bool clear_all_soft_refs, GCCause::Cause cause) {
assert(Thread::current()->is_ConcurrentGC_thread(),
"A CMS asynchronous collection is only allowed on a CMS thread.");
GenCollectedHeap* gch = GenCollectedHeap::heap();
{
bool safepoint_check = Mutex::_no_safepoint_check_flag;
//獲取Heap_lock鎖
MutexLockerEx hl(Heap_lock, safepoint_check);
//獲取FreelistLock鎖
FreelistLocker fll(this);
//獲取CGC_lock鎖
MutexLockerEx x(CGC_lock, safepoint_check);
//UseAsyncConcMarkSweepGC表示是否使用異步的垃圾回收,默認爲true
if (_foregroundGCIsActive || !UseAsyncConcMarkSweepGC) {
//如果前臺GC正在執行,則退出
assert(!_foregroundGCShouldWait, "Should be clear");
return;
} else {
assert(_collectorState == Idling, "Should be idling before start.");
//將_collectorState由Idling改爲InitialMarking
_collectorState = InitialMarking;
//通知GC開始
register_gc_start(cause);
//清除擴展原因
clear_expansion_cause();
//元空間的GC標識置爲false
MetaspaceGC::set_should_concurrent_collect(false);
}
//判斷是否需要卸載Class
update_should_unload_classes();
//後臺GC觸發的GC,所以將_full_gc_requested置爲false
_full_gc_requested = false; // acks all outstanding full gc requests
_full_gc_cause = GCCause::_no_gc;
//增加總的GC次數
gch->increment_total_full_collections(); // ... starting a collection cycle
_collection_count_start = gch->total_full_collections();
}
// Used for PrintGC
size_t prev_used = 0;
if (PrintGC && Verbose) {
//GC開始前的內存使用量
prev_used = _cmsGen->used(); // XXXPERM
}
while (_collectorState != Idling) {
if (TraceCMSState) {
gclog_or_tty->print_cr("Thread " INTPTR_FORMAT " in CMS state %d",
Thread::current(), _collectorState);
}
{
//獲取CMS Token
CMSTokenSync x(true); // is cms thread
//如果前臺GC在進行中,則不斷循環等待GC結束,然後返回true
//返回false表示沒有執行前臺GC
if (waitForForegroundGC()) {
//前臺GC完成了,不需要再進行後臺GC了,直接返回
assert(_foregroundGCShouldWait == false, "We set it to false in "
"waitForForegroundGC()");
if (TraceCMSState) {
gclog_or_tty->print_cr("CMS Thread " INTPTR_FORMAT
" exiting collection CMS state %d",
Thread::current(), _collectorState);
}
return;
} else {
//檢查_collectorState,正常不會是Idling,因爲執行後臺GC只有一個線程,CMSThread
if (_collectorState == Idling) {
break;
}
}
}
//waitForForegroundGC方法中將該標誌置爲true,表示開始執行後臺GC
assert(_foregroundGCShouldWait, "Foreground collector, if active, "
"should be waiting");
switch (_collectorState) {
case InitialMarking:
{
//檢查前臺GC是否開始,如果開始則讓出執行權限
ReleaseForegroundGC x(this);
//記錄GC開始
stats().record_cms_begin();
//通過VMThread執行InitialMarking步驟,底層還是調用checkpointRootsInitial方法
VM_CMS_Initial_Mark initial_mark_op(this);
VMThread::execute(&initial_mark_op);
}
break;
case Marking:
//從根節點標記
if (markFromRoots(true)) { // we were successful
assert(_collectorState == Precleaning, "Collector state should "
"have changed");
} else {
assert(_foregroundGCIsActive, "Internal state inconsistency");
}
break;
case Precleaning:
if (UseAdaptiveSizePolicy) {
//記錄preclean開始
size_policy()->concurrent_precleaning_begin();
}
//執行預清理
preclean();
if (UseAdaptiveSizePolicy) {
//記錄preclean結束
size_policy()->concurrent_precleaning_end();
}
assert(_collectorState == AbortablePreclean ||
_collectorState == FinalMarking,
"Collector state should have changed");
break;
case AbortablePreclean:
if (UseAdaptiveSizePolicy) {
size_policy()->concurrent_phases_resume();
}
//執行可終止的清理
abortable_preclean();
if (UseAdaptiveSizePolicy) {
size_policy()->concurrent_precleaning_end();
}
assert(_collectorState == FinalMarking, "Collector state should "
"have changed");
break;
case FinalMarking:
{
//檢查前臺GC是否開始,如果開始則讓出執行權限
ReleaseForegroundGC x(this);
//通過VMThread執行最終標記,底層是調用checkpointRootsFinal方法
VM_CMS_Final_Remark final_remark_op(this);
VMThread::execute(&final_remark_op);
}
assert(_foregroundGCShouldWait, "block post-condition");
break;
case Sweeping:
if (UseAdaptiveSizePolicy) {
//記錄sweep開始
size_policy()->concurrent_sweeping_begin();
}
//執行清理
sweep(true);
assert(_collectorState == Resizing, "Collector state change "
"to Resizing must be done under the free_list_lock");
_full_gcs_since_conc_gc = 0;
// Stop the timers for adaptive size policy for the concurrent phases
if (UseAdaptiveSizePolicy) {
//記錄sweep結束
size_policy()->concurrent_sweeping_end();
size_policy()->concurrent_phases_end(gch->gc_cause(),
gch->prev_gen(_cmsGen)->capacity(),
_cmsGen->free());
}
case Resizing: {
{
//檢查前臺GC是否開始
ReleaseForegroundGC x(this); // unblock FG collection
//獲取鎖
MutexLockerEx y(Heap_lock, Mutex::_no_safepoint_check_flag);
CMSTokenSync z(true); // not strictly needed.
if (_collectorState == Resizing) {
//重新計算容量
compute_new_size();
//保存堆內存使用情況
save_heap_summary();
//修改狀態
_collectorState = Resetting;
} else {
assert(_collectorState == Idling, "The state should only change"
" because the foreground collector has finished the collection");
}
}
break;
}
case Resetting:
//重置CMSCollector的狀態
reset(true);
assert(_collectorState == Idling, "Collector state should "
"have changed");
MetaspaceGC::set_should_concurrent_collect(false);
stats().record_cms_end();
break;
case Idling:
default:
ShouldNotReachHere();
break;
}
if (TraceCMSState) {
gclog_or_tty->print_cr(" Thread " INTPTR_FORMAT " done - next CMS state %d",
Thread::current(), _collectorState);
}
assert(_foregroundGCShouldWait, "block post-condition");
}
//更新計數器
collector_policy()->counters()->update_counters();
{
//獲取鎖CGC_lock
MutexLockerEx x(CGC_lock, Mutex::_no_safepoint_check_flag);
_foregroundGCShouldWait = false;
if (_foregroundGCIsActive) {
//讓出使用權限
CGC_lock->notify();
}
assert(!ConcurrentMarkSweepThread::cms_thread_has_cms_token(),
"Possible deadlock");
}
if (TraceCMSState) {
gclog_or_tty->print_cr("CMS Thread " INTPTR_FORMAT
" exiting collection CMS state %d",
Thread::current(), _collectorState);
}
if (PrintGC && Verbose) {
_cmsGen->print_heap_change(prev_used);
}
}
//如果前臺GC開始了則不斷循環等待,直到前臺GC完成
bool CMSCollector::waitForForegroundGC() {
bool res = false;
//校驗已經獲取了CMS Token
assert(ConcurrentMarkSweepThread::cms_thread_has_cms_token(),
"CMS thread should have CMS token");
//獲取鎖CGC_lock
MutexLockerEx x(CGC_lock, Mutex::_no_safepoint_check_flag);
_foregroundGCShouldWait = true;
if (_foregroundGCIsActive) {
//如果前臺GC在執行中,則讓出執行權限
res = true;
_foregroundGCShouldWait = false;
//釋放CMS Token
ConcurrentMarkSweepThread::clear_CMS_flag(
ConcurrentMarkSweepThread::CMS_cms_has_token);
ConcurrentMarkSweepThread::set_CMS_flag(
ConcurrentMarkSweepThread::CMS_cms_wants_token);
//喚醒CGC_lock上等待的線程,從而前臺GC可獲取CMS Token
CGC_lock->notify();
if (TraceCMSState) {
gclog_or_tty->print_cr("CMS Thread " INTPTR_FORMAT " waiting at CMS state %d",
Thread::current(), _collectorState);
}
//不斷循環等待直到_foregroundGCIsActive變成false,即前臺GC結束
while (_foregroundGCIsActive) {
CGC_lock->wait(Mutex::_no_safepoint_check_flag);
}
//等待結束,前臺GC完成,設置CMS_flag,表示已獲取CMS Token
ConcurrentMarkSweepThread::set_CMS_flag(
ConcurrentMarkSweepThread::CMS_cms_has_token);
ConcurrentMarkSweepThread::clear_CMS_flag(
ConcurrentMarkSweepThread::CMS_cms_wants_token);
}
if (TraceCMSState) {
gclog_or_tty->print_cr("CMS Thread " INTPTR_FORMAT " continuing at CMS state %d",
Thread::current(), _collectorState);
}
return res;
}
上述代碼中的FreelistLocker用於獲取FreelistLock,其定義如下:
ReleaseForegroundGC用於檢查前臺GC是否觸發,如果觸發了則喚醒在CGC_lock上等待的VMThread,方便其進入安全點,從而達到stop the world的目標,其定義如下:
注意這裏無論_foregroundGCIsActive是否爲true,都將_foregroundGCShouldWait置爲了false,這是因爲後臺GC在執行initial mark, final remark這兩個步驟時需要stop the world,停止所有其他線程的執行,爲了避免執行前臺GC的VMThread因爲 _foregroundGCShouldWait 處於阻塞狀態而無法進入到安全點而導致無法達到stop the world的效果,所以這裏臨時將_foregroundGCShouldWait置爲false,等initial mark或者final remark執行完成就將_foregroundGCShouldWait置爲true。
5、VM_CMS_Operation
VM_CMS_Operation是後面兩個類的父類,其類繼承關係如下:
VM_Operation的實現參考《Hotspot 垃圾回收之VM_Operation 源碼解析》,VM_CMS_Operation增加了兩個屬性:
- CMSCollector* _collector; //實際執行相關GC邏輯的CMSCollector實例
- bool _prologue_succeeded; // doit_prologue 是否執行成功,只有這個成功,纔會執行doit方法
重點關注其doit_prologue和doit_epilogue方法的實現,這兩方法是doit執行前後調用的方法,VM_CMS_Operation未提供doit方法的默認實現,注意這兩方法都是由調用VMThread::execute的CMSThread線程執行的,VMThread只負責執行doit方法,如下:
VM_CMS_Operation(CMSCollector* collector):
_collector(collector),
_prologue_succeeded(false) {}
bool VM_CMS_Operation::doit_prologue() {
//校驗當前線程是CMS Thread
assert(Thread::current()->is_ConcurrentGC_thread(), "just checking");
//校驗foregroundGCShouldWait屬性爲false,在ReleaseForegroundGC的構造方法中將該屬性置爲false
assert(!CMSCollector::foregroundGCShouldWait(), "Possible deadlock");
//前臺GC未執行,所以不需要跟執行前臺GC的VTThread通過CMS Token同步,cms_thread_has_cms_token就返回false
assert(!ConcurrentMarkSweepThread::cms_thread_has_cms_token(),
"Possible deadlock");
//如果需要PLL鎖
if (needs_pll()) {
//獲取鎖
acquire_pending_list_lock();
}
//獲取Heap_lock鎖
Heap_lock->lock();
if (lost_race()) {
//如果其他線程已經完成GC,則釋放Heap_lock,PLL鎖
assert(_prologue_succeeded == false, "Initialized in c'tor");
Heap_lock->unlock();
if (needs_pll()) {
release_and_notify_pending_list_lock();
}
} else {
//將_prologue_succeeded置爲true,默認爲false
_prologue_succeeded = true;
}
return _prologue_succeeded;
}
void VM_CMS_Operation::acquire_pending_list_lock() {
//PLL就是pending list lock的簡稱,底層實際就是一個偏向鎖BasicLock
SurrogateLockerThread* slt = ConcurrentMarkSweepThread::slt();
if (slt != NULL) {
//獲取PLL鎖
slt->manipulatePLL(SurrogateLockerThread::acquirePLL);
} else {
SurrogateLockerThread::report_missing_slt();
}
}
bool VM_CMS_Operation::lost_race() const {
if (CMSCollector::abstract_state() == CMSCollector::Idling) {
//校驗_collectorState狀態,如果是Idling說明已經完成GC
return true;
}
//校驗狀態是否正確,legal_state方法返回當前Operation支持的正確狀態
assert(CMSCollector::abstract_state() == legal_state(),
"Inconsistent collector state?");
return false;
}
static CollectorState abstract_state() { return _collectorState; }
void VM_CMS_Operation::release_and_notify_pending_list_lock() {
ConcurrentMarkSweepThread::slt()->
manipulatePLL(SurrogateLockerThread::releaseAndNotifyPLL);
}
void VM_CMS_Operation::doit_epilogue() {
assert(Thread::current()->is_ConcurrentGC_thread(), "just checking");
assert(!CMSCollector::foregroundGCShouldWait(), "Possible deadlock");
assert(!ConcurrentMarkSweepThread::cms_thread_has_cms_token(),
"Possible deadlock");
//釋放Heap_lock,PLL鎖
Heap_lock->unlock();
if (needs_pll()) {
release_and_notify_pending_list_lock();
}
}
6、VM_CMS_Initial_Mark / VM_CMS_Final_Remark
這兩個都繼承自VM_CMS_Operation,分別用來執行CMS_Initial_Mark和CMS_Final_Remark任務,重點關注其doit方法的實現,其底層核心實現跟collect_in_foreground中同樣步驟的實現是一樣的,如下:
virtual const CMSCollector::CollectorState legal_state() const {
return CMSCollector::InitialMarking;
}
virtual const bool needs_pll() const {
return false;
}
void VM_CMS_Initial_Mark::doit() {
if (lost_race()) {
//如果GC已完成
return;
}
//通知GC中斷開始,即中斷CMS Thread的GC,轉交給VMThread執行
_collector->_gc_timer_cm->register_gc_pause_start("Initial Mark");
//設置gc_cause
GenCollectedHeap* gch = GenCollectedHeap::heap();
GCCauseSetter gccs(gch, GCCause::_cms_initial_mark);
VM_CMS_Operation::verify_before_gc();
//將CollectedHeap的_is_gc_active屬性置true
IsGCActiveMark x; // stop-world GC active
//執行具體的GC邏輯
_collector->do_CMS_operation(CMSCollector::CMS_op_checkpointRootsInitial, gch->gc_cause());
VM_CMS_Operation::verify_after_gc();
//通知GC中斷結束,GC即將轉交給CMSThread繼續執行
_collector->_gc_timer_cm->register_gc_pause_end();
}
virtual const CMSCollector::CollectorState legal_state() const {
return CMSCollector::FinalMarking;
}
virtual const bool needs_pll() const {
return true;
}
//代碼邏輯跟VM_CMS_Initial_Mark基本一致
void VM_CMS_Final_Remark::doit() {
if (lost_race()) {
// Nothing to do.
return;
}
_collector->_gc_timer_cm->register_gc_pause_start("Final Mark");
GenCollectedHeap* gch = GenCollectedHeap::heap();
GCCauseSetter gccs(gch, GCCause::_cms_final_remark);
VM_CMS_Operation::verify_before_gc();
IsGCActiveMark x; // stop-world GC active
_collector->do_CMS_operation(CMSCollector::CMS_op_checkpointRootsFinal, gch->gc_cause());
VM_CMS_Operation::verify_after_gc();
_collector->save_heap_summary();
_collector->_gc_timer_cm->register_gc_pause_end();
}
void VM_CMS_Operation::verify_before_gc() {
//VerifyBeforeGC表示是否需要在GC前執行校驗邏輯,默認爲false
if (VerifyBeforeGC &&
GenCollectedHeap::heap()->total_collections() >= VerifyGCStartAt) {
GCTraceTime tm("Verify Before", false, false, _collector->_gc_timer_cm, _collector->_gc_tracer_cm->gc_id());
HandleMark hm;
FreelistLocker x(_collector);
MutexLockerEx y(_collector->bitMapLock(), Mutex::_no_safepoint_check_flag);
Universe::heap()->prepare_for_verify();
Universe::verify();
}
}
void VM_CMS_Operation::verify_after_gc() {
if (VerifyAfterGC &&
GenCollectedHeap::heap()->total_collections() >= VerifyGCStartAt) {
GCTraceTime tm("Verify After", false, false, _collector->_gc_timer_cm, _collector->_gc_tracer_cm->gc_id());
HandleMark hm;
FreelistLocker x(_collector);
MutexLockerEx y(_collector->bitMapLock(), Mutex::_no_safepoint_check_flag);
Universe::verify();
}
}
void CMSCollector::do_CMS_operation(CMS_op_type op, GCCause::Cause gc_cause) {
TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty);
GCTraceTime t(GCCauseString("GC", gc_cause), PrintGC, !PrintGCDetails, NULL, _gc_tracer_cm->gc_id());
TraceCollectorStats tcs(counters());
//根據CMS_op_type執行不同的邏輯
switch (op) {
case CMS_op_checkpointRootsInitial: {
SvcGCMarker sgcm(SvcGCMarker::OTHER);
checkpointRootsInitial(true); // asynch
if (PrintGC) {
_cmsGen->printOccupancy("initial-mark");
}
break;
}
case CMS_op_checkpointRootsFinal: {
SvcGCMarker sgcm(SvcGCMarker::OTHER);
checkpointRootsFinal(true, // asynch
false, // !clear_all_soft_refs
false); // !init_mark_was_synchronous
if (PrintGC) {
_cmsGen->printOccupancy("remark");
}
break;
}
default:
fatal("No such CMS_op");
}
}
上述代碼中IsGCActiveMark類用來臨時將CollectedHeap的_is_gc_active屬性置true,其定義如下:
SvcGCMarker用來通知GC開始和結束,notify_gc_begin和notify_gc_end實際就是打日誌而已,其定義如下:
7、shouldConcurrentCollect
該方法由CMSThread調用,用來判斷是否需要執行GC,如果需要則調用collect_in_background方法執行GC,其實現如下:
bool CMSCollector::shouldConcurrentCollect() {
if (_full_gc_requested) {
//如果需要full GC
if (Verbose && PrintGCDetails) {
gclog_or_tty->print_cr("CMSCollector: collect because of explicit "
" gc request (or gc_locker)");
}
return true;
}
//獲取FreelistLock鎖
FreelistLocker x(this);
//打印老年代的內存使用情況
if (PrintCMSInitiationStatistics && stats().valid()) {
gclog_or_tty->print("CMSCollector shouldConcurrentCollect: ");
gclog_or_tty->stamp();
gclog_or_tty->cr();
stats().print_on(gclog_or_tty);
gclog_or_tty->print_cr("time_until_cms_gen_full %3.7f",
stats().time_until_cms_gen_full());
gclog_or_tty->print_cr("free=" SIZE_FORMAT, _cmsGen->free());
gclog_or_tty->print_cr("contiguous_available=" SIZE_FORMAT,
_cmsGen->contiguous_available());
gclog_or_tty->print_cr("promotion_rate=%g", stats().promotion_rate());
gclog_or_tty->print_cr("cms_allocation_rate=%g", stats().cms_allocation_rate());
gclog_or_tty->print_cr("occupancy=%3.7f", _cmsGen->occupancy());
gclog_or_tty->print_cr("initiatingOccupancy=%3.7f", _cmsGen->initiating_occupancy());
gclog_or_tty->print_cr("cms_time_since_begin=%3.7f", stats().cms_time_since_begin());
gclog_or_tty->print_cr("cms_time_since_end=%3.7f", stats().cms_time_since_end());
gclog_or_tty->print_cr("metadata initialized %d",
MetaspaceGC::should_concurrent_collect());
}
// ------------------------------------------------------------------
//UseCMSInitiatingOccupancyOnly表示是否只使用InitiatingOccupancy作爲判斷是否GC的標準,默認爲false
if (!UseCMSInitiatingOccupancyOnly) {
//如果CMSStas的數據是有效的
if (stats().valid()) {
//如果當前時間與上一次垃圾回收的時間間隔超過了歷史上的時間間隔
if (stats().time_until_cms_start() == 0.0) {
return true;
}
} else {
//判斷使用率是否超過設定的值
if (_cmsGen->occupancy() >= _bootstrap_occupancy) {
if (Verbose && PrintGCDetails) {
gclog_or_tty->print_cr(
" CMSCollector: collect for bootstrapping statistics:"
" occupancy = %f, boot occupancy = %f", _cmsGen->occupancy(),
_bootstrap_occupancy);
}
return true;
}
}
}
//cmsGen認爲應該GC
if (_cmsGen->should_concurrent_collect()) {
if (Verbose && PrintGCDetails) {
gclog_or_tty->print_cr("CMS old gen initiated");
}
return true;
}
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(true /* consult_young */)) {
if (Verbose && PrintGCDetails) {
gclog_or_tty->print("CMSCollector: collect because incremental collection will fail ");
}
return true;
}
//如果元空間需要GC
if (MetaspaceGC::should_concurrent_collect()) {
if (Verbose && PrintGCDetails) {
gclog_or_tty->print("CMSCollector: collect for metadata allocation ");
}
return true;
}
// CMSTriggerInterval表示CMS觸發的間隔時間,默認值是-1
if (CMSTriggerInterval >= 0) {
if (CMSTriggerInterval == 0) {
//如果等於0,表示每次都觸發
return true;
}
//否則檢測當前時間與上一次GC的時間間隔是否超過限制
if (stats().cms_time_since_begin() >= (CMSTriggerInterval / ((double) MILLIUNITS))) {
if (Verbose && PrintGCDetails) {
if (stats().valid()) {
gclog_or_tty->print_cr("CMSCollector: collect because of trigger interval (time since last begin %3.7f secs)",
stats().cms_time_since_begin());
} else {
gclog_or_tty->print_cr("CMSCollector: collect because of trigger interval (first collection)");
}
}
return true;
}
}
return false;
}
8、總結
CMS下觸發GC的有兩種方式,一種是同步的,內存分配失敗或者調用System.gc()方法會觸發同步的GC,GC的具體步驟會由VMThread執行完成,也成前臺GC(foreground GC);一種是異步的,CMSThread在後臺會按照一定的規則不斷的輪詢判斷是否需要GC,如果需要則執行GC,也成後臺GC(background GC)不過有兩個步驟initial mark, final remark,需要stop the world後才能執行,CMSThread在執行這兩個步驟時會將其轉交給VMThread執行。
爲了保證VMThread和CMS Thread不會並行的執行GC,就需要在兩者之間做同步,主要通過_foregroundGCIsActive和_foregroundGCShouldWait,CGC_lock來實現的,_foregroundGCIsActive爲true表示前臺GC被觸發了,如果此時_foregroundGCShouldWait爲true則表示後臺GC正在執行某個GC步驟,執行前臺GC的VMThead會在CGC_lock上不斷輪詢等待直到_foregroundGCShouldWait變爲false,等待結束後會根據當前GC的狀態_collectorState來決定執行下一個步驟,大部分情況下會繼續處理後臺GC的剩餘步驟,但是需要清理所有軟引用且老年代不需要壓縮且FinalMarking步驟完成了,則需要重新開啓一輪新的GC,重新查找待處理的Reference實例。等前臺GC結束後會將_foregroundGCIsActive置爲false。
後臺GC開始執行時會檢查_foregroundGCIsActive是否爲true,如果是則返回;如果是false,則開始循環處理GC的各個步驟,每次循環前都要檢查_foregroundGCIsActive是否爲true,如果爲true,則_foregroundGCShouldWait置爲false,然後在CGC_lock上等待直到_foregroundGCIsActive變成false,即等待前臺GC結束,然後返回;如果爲false,則將_foregroundGCShouldWait屬性置爲true,開始處理下一個步驟。有兩個步驟比較特殊,initial mark, final remark,在開始執行時還會再檢查一遍_foregroundGCIsActive是否爲true,如果爲true,則將在CGC_lock上等待的VMThread喚醒,方便其進入安全點,達到stop the world的目的。