full gc是g1正常的gc cycle回收無力的情況下進行的,相對來說比較簡單
主要入口代碼在 g1CollectedHeap.cpp
do_full_collection
bool G1CollectedHeap::do_full_collection(bool explicit_gc,
bool clear_all_soft_refs,
bool do_maximum_compaction) {
assert_at_safepoint_on_vm_thread();
//檢查jni lock
if (GCLocker::check_active_before_gc()) {
// Full GC was not completed.
return false;
}
//判斷系統(tǒng)是否需要回收所有軟連接,主要看空間緊急程度
const bool do_clear_all_soft_refs = clear_all_soft_refs ||
soft_ref_policy()->should_clear_all_soft_refs();
G1FullCollector collector(this, explicit_gc, do_clear_all_soft_refs, do_maximum_compaction);
GCTraceTime(Info, gc) tm("Pause Full", NULL, gc_cause(), true);
//準備階段,主要是打印日志,停止cycle,停止并發(fā)標記,關(guān)閉活躍區(qū)域等
collector.prepare_collection();
collector.collect();
//清理標記狀態(tài),記錄full gc結(jié)束日志等
collector.complete_collection();
// Full collection was successfully completed.
return true;
}
full gc分為四個階段,對應(yīng)四個task,看對應(yīng)的work方法即可
G1FullGCMarkTask,G1FullGCPrepareTask,G1FullGCAdjustTask,G1FullGCCompactTask
void G1FullCollector::collect() {
//標記,<<深入理解jvm虛擬機>>書上沒看到這種full gc標記過程
phase1_mark_live_objects();
verify_after_marking();
// Don't add any more derived pointers during later phases
//棧上的派生類指針表進行關(guān)閉
deactivate_derived_pointers();
//壓縮準備,判斷region空間是否需要壓縮,存入一個隊列compaction queue
phase2_prepare_compaction();
//指針調(diào)整,新region地址更新
phase3_adjust_pointers();
//壓縮region,處理第二步的東西
phase4_do_compaction();
}
phase1_mark_live_objects
使用到了gc線程來進行的標記,就是初始化g1heap出現(xiàn)的_worker,線程中再使用G1FullGCMarker的線程
void G1FullCollector::phase1_mark_live_objects() {
// Recursively traverse all live objects and mark them.
GCTraceTime(Info, gc, phases) info("Phase 1: Mark live objects", scope()->timer());
{
// Do the actual marking.
//標記,不是并發(fā)的,在prepare階段concurrent_cycle_abort關(guān)了
G1FullGCMarkTask marking_task(this);
//實際調(diào)用就是task的work方法
run_task(&marking_task);
}
{ //引用處理器ReferenceProcessor,一種是并發(fā)的_ref_processor_cm還有就是這里的_ref_processor_stw
//stw的開啟會關(guān)閉cm的,并且開啟單單線程,full gc中發(fā)現(xiàn)任何引用都會記錄進來
uint old_active_mt_degree = reference_processor()->num_queues();
reference_processor()->set_active_mt_degree(workers());
GCTraceTime(Debug, gc, phases) debug("Phase 1: Reference Processing", scope()->timer());
// Process reference objects found during marking.
//標記過程中出現(xiàn)的引用處理
ReferenceProcessorPhaseTimes pt(scope()->timer(), reference_processor()->max_num_queues());
G1FullGCRefProcProxyTask task(*this, reference_processor()->max_num_queues());
//處理引用,按照軟強弱虛的順序處理
const ReferenceProcessorStats& stats = reference_processor()->process_discovered_references(task, pt);
scope()->tracer()->report_gc_reference_stats(stats);
pt.print_all_references();
assert(marker(0)->oop_stack()->is_empty(), "Should be no oops on the stack");
reference_processor()->set_active_mt_degree(old_active_mt_degree);
}
// Weak oops cleanup.
// 對象只有一個弱引用的話就要被回收
// 這里處理會開多個線程,將弱引用地址所指的對象循環(huán)查看,不是空的且不是存活的對象就釋放引用
{
GCTraceTime(Debug, gc, phases) debug("Phase 1: Weak Processing", scope()->timer());
WeakProcessor::weak_oops_do(_heap->workers(), &_is_alive, &do_nothing_cl, 1);
}
// Class unloading and cleanup.
// classloader卸載class,要從符號表移除
if (ClassUnloading) {
GCTraceTime(Debug, gc, phases) debug("Phase 1: Class Unloading and Cleanup", scope()->timer());
// Unload classes and purge the SystemDictionary.
bool purged_class = SystemDictionary::do_unloading(scope()->timer());
_heap->complete_cleaning(&_is_alive, purged_class);
}
scope()->tracer()->report_object_count_after_gc(&_is_alive);
}
多線程處理標記,GcRoots,注意這里不是說傳統(tǒng)意義的多線程來處理,而是我們需要對每個線程進行處理
void G1FullGCMarkTask::work(uint worker_id) {
Ticks start = Ticks::now();
ResourceMark rm;
G1FullGCMarker* marker = collector()->marker(worker_id);
MarkingCodeBlobClosure code_closure(marker->mark_closure(), !CodeBlobToOopClosure::FixRelocations);
//ClassUnloading默認為true
if (ClassUnloading) {
//處理gcRoots
_root_processor.process_strong_roots(marker->mark_closure(),
marker->cld_closure(),
&code_closure);
} else {
_root_processor.process_all_roots(marker->mark_closure(),
marker->cld_closure(),
&code_closure);
}
// Mark stack is populated, now process and drain it.
//之前遍歷roots生成的stack進行抽取處理
//通過mark word將存活的對象記錄到_mark_stats_cache
marker->complete_marking(collector()->oop_queue_set(), collector()->array_queue_set(), &_terminator);
marker->flush_mark_stats_cache();
// This is the point where the entire marking should have completed.
assert(marker->oop_stack()->is_empty(), "Marking should have completed");
assert(marker->objarray_stack()->is_empty(), "Array marking should have completed");
log_task("Marking task", worker_id, start);
}
process_strong_roots標記gcRoots
void G1RootProcessor::process_strong_roots(OopClosure* oops,
CLDClosure* clds,
CodeBlobClosure* blobs) {
StrongRootsClosures closures(oops, clds, blobs);
//1.清除本地方法nmethod線程棧外的對象
//2.重新映射對象
//3.標記存活對象
process_java_roots(&closures, NULL, 0);
process_vm_roots(&closures, NULL, 0);
// CodeCache is already processed in java roots
// refProcessor is not needed since we are inside a safe point
_process_strong_tasks.all_tasks_claimed(G1RP_PS_CodeCache_oops_do,
G1RP_PS_refProcessor_oops_do);
}
先看StrongRootsClosures closures(oops, clds, blobs);
這里三個參數(shù)的類型為G1MarkAndPushClosure,CLDToOopClosure,MarkingCodeBlobClosure
對應(yīng)獲取方法strong_oops(),strong_clds(),strong_codeblobs()
對應(yīng)的root為java引用,類加載器對象,方法對象
實際運行的就是這些closure
complete_marking 處理前一步從強引用,類加載器,方法區(qū)獲得的gcRoots對象
void G1FullGCMarker::complete_marking(OopQueueSet* oop_stacks,
ObjArrayTaskQueueSet* array_stacks,
TaskTerminator* terminator) {
do {
//處理標記
drain_stack();
ObjArrayTask steal_array;
//從其他worker線程取任務(wù)繼續(xù)處理
if (array_stacks->steal(_worker_id, steal_array)) {
follow_array_chunk(objArrayOop(steal_array.obj()), steal_array.index());
} else {
oop steal_oop;
if (oop_stacks->steal(_worker_id, steal_oop)) {
follow_object(steal_oop);
}
}
} while (!is_empty() || !terminator->offer_termination());
}
//處理
void G1FullGCMarker::drain_stack() {
do {
oop obj;
//從之前gcroots標記的_oop_stack獲取對象到obj
while (pop_object(obj)) {
assert(_bitmap->is_marked(obj), "must be marked");
//標記成員,也就是可達對象,mark_push后再while循環(huán),不可達的對象最后會被回收
follow_object(obj);
}
// Process ObjArrays one at a time to avoid marking stack bloat.
ObjArrayTask task;
if (pop_objarray(task)) {
follow_array_chunk(objArrayOop(task.obj()), task.index());
}
} while (!is_empty());
}
phase2_prepare_compaction
直接看G1FullGCPrepareTask核心代碼
bool G1FullGCPrepareTask::G1CalculatePointersClosure::do_heap_region(HeapRegion* hr) {
bool force_not_compacted = false;
if (should_compact(hr)) {
//首先通過hrm region管理器查看對應(yīng)region是否已經(jīng)pinned(歸檔或者是大對象),再檢查region壓縮的臨界值
assert(!hr->is_humongous(), "moving humongous objects not supported.");
//到達臨界值沒有鎖定的region放入隊列
prepare_for_compaction(hr);
} else {
// There is no need to iterate and forward objects in pinned regions ie.
// prepare them for compaction. The adjust pointers phase will skip
// work for them.
assert(hr->containing_set() == nullptr, "already cleared by PrepareRegionsClosure");
if (hr->is_humongous()) {
oop obj = cast_to_oop(hr->humongous_start_region()->bottom());
//大對象檢查是否標記,不在標記的進行回收且放入回收隊列
if (!_bitmap->is_marked(obj)) {
free_pinned_region<true>(hr);
}
} else if (hr->is_open_archive()) {
bool is_empty = _collector->live_words(hr->hrm_index()) == 0;
if (is_empty) {
free_pinned_region<false>(hr);
}
} else if (hr->is_closed_archive()) {
// nothing to do with closed archive region
} else {
//MarkSweepDeadRatio默認5
assert(MarkSweepDeadRatio > 0,
"only skip compaction for other regions when MarkSweepDeadRatio > 0");
// Too many live objects; skip compacting it.
_collector->update_from_compacting_to_skip_compacting(hr->hrm_index());
//region如果是年輕代的,需要創(chuàng)建Block Offset Table
if (hr->is_young()) {
// G1 updates the BOT for old region contents incrementally, but young regions
// lack BOT information for performance reasons.
// Recreate BOT information of high live ratio young regions here to keep expected
// performance during scanning their card tables in the collection pauses later.
hr->update_bot();
}
log_trace(gc, phases)("Phase 2: skip compaction region index: %u, live words: " SIZE_FORMAT,
hr->hrm_index(), _collector->live_words(hr->hrm_index()));
}
}
// Reset data structures not valid after Full GC.
//清除rem_set與cardtable信息
reset_region_metadata(hr);
return false;
}
如果準備階段發(fā)現(xiàn)!task.has_freed_regions()
regions不夠用,就需要用到serial的gc,調(diào)用prepare_serial_compaction
phase3_adjust_pointers
G1FullGCAdjustTask
void G1FullGCAdjustTask::work(uint worker_id) {
Ticks start = Ticks::now();
ResourceMark rm;
// Adjust preserved marks first since they are not balanced.
G1FullGCMarker* marker = collector()->marker(worker_id);\
//調(diào)整stack中的對象地址,前面的region已經(jīng)回收了
marker->preserved_stack()->adjust_during_full_gc();
// Adjust the weak roots.
if (!Atomic::cmpxchg(&_references_done, false, true)) {
G1CollectedHeap::heap()->ref_processor_stw()->weak_oops_do(&_adjust);
}
AlwaysTrueClosure always_alive;
_weak_proc_task.work(worker_id, &always_alive, &_adjust);
CLDToOopClosure adjust_cld(&_adjust, ClassLoaderData::_claim_strong);
CodeBlobToOopClosure adjust_code(&_adjust, CodeBlobToOopClosure::FixRelocations);
//回到了第一個標記階段
_root_processor.process_all_roots(&_adjust, &adjust_cld, &adjust_code);
// Now adjust pointers region by region
//逐個region進行處理
G1AdjustRegionClosure blk(collector(), worker_id);
G1CollectedHeap::heap()->heap_region_par_iterate_from_worker_offset(&blk, &_hrclaimer, worker_id);
log_task("Adjust task", worker_id, start);
}
phase4_do_compaction
void G1FullGCCompactTask::work(uint worker_id) {
Ticks start = Ticks::now();
GrowableArray<HeapRegion*>* compaction_queue = collector()->compaction_point(worker_id)->regions();
for (GrowableArrayIterator<HeapRegion*> it = compaction_queue->begin();
it != compaction_queue->end();
++it) {
//將標記對象取出后,移動到目標地址,隨后清除next_mark_bitmap
compact_region(*it);
}
//重新設(shè)置region是否需要壓縮
G1ResetSkipCompactingClosure hc(collector());
G1CollectedHeap::heap()->heap_region_par_iterate_from_worker_offset(&hc, &_claimer, worker_id);
log_task("Compaction task", worker_id, start);
}
壓縮就是復(fù)制,每一個對象存了新地址的
size_t G1FullGCCompactTask::G1CompactRegionClosure::apply(oop obj) {
size_t size = obj->size();
HeapWord* destination = cast_from_oop<HeapWord*>(obj->forwardee());
if (destination == NULL) {
// Object not moving
return size;
}
// copy object and reinit its mark
HeapWord* obj_addr = cast_from_oop<HeapWord*>(obj);
assert(obj_addr != destination, "everything in this pass should be moving");
Copy::aligned_conjoint_words(obj_addr, destination, size);
//初始化就是更新對象mark word
cast_to_oop(destination)->init_mark();
assert(cast_to_oop(destination)->klass() != NULL, "should have a class");
return size;
}