G1CollectedHeap の Minor GC 処理は, VM_G1IncCollectionPause::doit() を呼び出すことで行われる (See: here for details).
実際の Minor GC 処理は, VM_G1IncCollectionPause::doit() から呼び出される G1CollectedHeap::do_collection_pause_at_safepoint() の中に実装されている. この G1CollectedHeap::do_collection_pause_at_safepoint() の処理は, 大きく分けると5つのフェーズからなる.
G1CollectorPolicy_BestRegionsFirst::choose_collection_set() で, GC 対象の region (collection set) を選択する
G1CollectedHeap::g1_process_strong_roots() で, strong root から辿れるオブジェクトを全てコピーする.
G1ParEvacuateFollowersClosure::do_void() で, コピーしたオブジェクトから再帰的に辿れる範囲を全てコピーする.
参照オブジェクト(java.lang.ref オブジェクト)の処理を行う
(See: here for details)
必要があれば concurrent mark 処理を開始させる
処理の並列化のために GangWorker クラスが使用されている (See: here for details). また, SharedHeap::process_strong_roots() 内では SubTasksDone による並列化も行われている (See: here for details).
なお, SharedHeap::process_strong_roots() 内で使用される SubTasksDone は SH_PS_NumElements 個の種別を管理している. それぞれの root 種別は以下の通り.
((cite: hotspot/src/share/vm/memory/sharedHeap.cpp))
// The set of potentially parallel tasks in strong root scanning.
enum SH_process_strong_roots_tasks {
SH_PS_Universe_oops_do,
SH_PS_JNIHandles_oops_do,
SH_PS_ObjectSynchronizer_oops_do,
SH_PS_FlatProfiler_oops_do,
SH_PS_Management_oops_do,
SH_PS_SystemDictionary_oops_do,
SH_PS_jvmti_oops_do,
SH_PS_StringTable_oops_do,
SH_PS_CodeCache_oops_do,
// Leave this one last.
SH_PS_NumElements
};
また, この SubTasksDone のコンストラクタ呼び出しに付いては SharedHeap::SharedHeap() 参照 (See: SharedHeap::SharedHeap()).
strong root から辿る処理において (= G1CollectedHeap::g1_process_strong_roots() から呼び出される処理において), 実際のコピー処理は以下の Closure によって行われる (concurrent mark を実施する場合は, mark bit への記入が必要になるため, 異なる Closure が使用される).
Minor GC 後に concurrent mark を実施する場合:
〃 を実施しない場合:
((cite: hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp))
G1ParScanExtRootClosure only_scan_root_cl(_g1h, &pss);
G1ParScanPermClosure only_scan_perm_cl(_g1h, &pss);
...
G1ParScanAndMarkExtRootClosure scan_mark_root_cl(_g1h, &pss);
G1ParScanAndMarkPermClosure scan_mark_perm_cl(_g1h, &pss);
...
VM_G1IncCollectionPause::doit_prologues() VM_G1IncCollectionPause::doit() -> G1CollectedHeap::do_collection_pause_at_safepoint() -> (1) 前準備を行う -> G1CollectedHeap::gc_prologue() -> G1CollectedHeap::release_mutator_alloc_region() -> G1CollectedHeap::save_marks() -> ConcurrentMark::drainAllSATBBuffers() (1) GC 対象の region (collection set) を選択する -> G1CollectorPolicy_BestRegionsFirst::choose_collection_set() (1) Copy 先となる region を選択する -> G1CollectedHeap::get_gc_alloc_regions() (1) GC (evacuation) を実行する -> G1CollectedHeap::evacuate_collection_set() -> G1ParTask::work() (<= parallel の場合は WorkGang::run_task() 経由で呼び出される) (1) root から直接参照されているオブジェクトを全て処理する. -> G1CollectedHeap::g1_process_strong_roots() -> SharedHeap::process_strong_roots() (なお使用するクロージャーは (Perm領域用/非Perm領域用のどちらも) G1ParCopyClosure. ポインタ配列用は G1ParScanPartialArrayClosure) (<= より正確には, G1ParCopyClosure を BufferingOopClosure や BufferingOopsInGenClosure でラッピングしたものが使われる) -> Universe::oops_do() -> (See: here for details) -> G1ParCopyClosure::do_oop() -> G1ParCopyClosure::do_oop_nv() -> G1ParCopyClosure::do_oop_work() -> G1ParCopyHelper::copy_to_survivor_space() (1) コピー先の領域にメモリを確保する -> G1ParScanThreadState::allocate() ParGCAllocBuffer::allocate() での確保を試みる. 失敗したら, G1ParScanThreadState::allocate_slow() での確保を行う (2) オブジェクトをコピーする (3) オブジェクト内のポインタを G1ParScanThreadState オブジェクト内に収集する. * 処理対象がものすごく長いポインタ配列の場合: (全部処理すると遅いのでここでは収集しない) -> set_partial_array_mask() * そうではない場合: -> oopDesc::oop_iterate_backwards() -> *Klass::oop_oop_iterate_backwards_v() または *Klass::oop_oop_iterate_backwards_nv() -> #TODO -> G1ParScanClosure::do_oop_nv() -> ReferenceProcessor::oops_do() -> (See: here for details) -> G1ParCopyClosure::do_oop() -> (同上) -> ReferenceProcessor::weak_oops_do() -> (See: here for details) -> G1ParCopyClosure::do_oop() -> (同上) -> JNIHandles::oops_do() -> (See: here for details) -> G1ParCopyClosure::do_oop() -> (同上) -> Threads::possibly_parallel_oops_do() または Threads::oops_do() -> (See: here for details) -> G1ParCopyClosure::do_oop() -> (同上) -> ObjectSynchronizer::oops_do() -> (See: here for details) -> G1ParCopyClosure::do_oop() -> (同上) -> FlatProfiler::oops_do() -> (See: here for details) -> G1ParCopyClosure::do_oop() -> (同上) -> Management::oops_do() -> (See: here for details) -> G1ParCopyClosure::do_oop() -> (同上) -> JvmtiExport::oops_do() -> (See: here for details) -> G1ParCopyClosure::do_oop() -> (同上) -> SystemDictionary::oops_do() または SystemDictionary::always_strong_oops_do() -> (See: here for details) -> G1ParCopyClosure::do_oop() -> (同上) -> StringTable::oops_do() -> (See: here for details) -> G1ParCopyClosure::do_oop() -> (同上) -> CodeCache::blobs_do() または CodeCache::scavenge_root_nmethods_do() -> (See: here for details) -> G1ParCopyClosure::do_oop() -> (同上) -> -> ConcurrentMark::oops_do() -> G1RemSet::oops_into_collection_set_do() -> G1RemSet::updateRS() -> G1CollectedHeap::iterate_dirty_card_closure() (なお使用するクロージャーは RefineRecordRefsIntoCSCardTableEntryClosure) -> DirtyCardQueueSet::apply_closure_to_completed_buffer() -> DirtyCardQueueSet::apply_closure_to_completed_buffer_helper() -> DirtyCardQueue::apply_closure_to_buffer() (なお使用するクロージャーは RefineRecordRefsIntoCSCardTableEntryClosure) -> RefineRecordRefsIntoCSCardTableEntryClosure::do_card_ptr() -> G1RemSet::concurrentRefineOneCard() -> ConcurrentG1Refine::cache_insert() -> G1RemSet::concurrentRefineOneCard_impl() -> HeapRegion::oops_on_card_seq_iterate_careful() (この場合のクロージャーは, check_for_refs_into_cset 引数が true なので, TriggerClosure をトリガーとして FilterIntoCSClosure を稼働させる InvokeIfNotTriggeredClosure を UpdateRSOrPushRefOopClosure と合成した Mux2Closure (をさらにFilterOutOfRegionClosureでくるんだもの. また, UpdateRSOrPushRefOopClosure 内では G1ParPushHeapRSClosure が使用される) -> oopDesc::oop_iterate() -> FilterOutOfRegionClosure::do_oop() -> FilterOutOfRegionClosure::do_oop_nv() -> Mux2Closure::do_oop() -> InvokeIfNotTriggeredClosure::do_oop() -> TriggerClosure::do_oop() -> FilterIntoCSClosure::do_oop() -> UpdateRSOrPushRefOopClosure::do_oop() -> UpdateRSOrPushRefOopClosure::do_oop_work() -> * -> G1ParPushHeapRSClosure::do_oop() * -> G1RemSet::par_write_ref() -> HeapRegionRemSet::add_reference(OopOrNarrowOopStar from, int tid) -> OtherRegionsTable::add_reference() -> OtherRegionsTable::find_region_table() -> 新しいエントリが必要なら以下の処理を行う. -> SparsePRT::add_card() (<= これは, 成功すればここでリターン) -> RSHashTable::add_card() -> RSHashTable::entry_for_region_ind_create() -> SparsePRTEntry::add_card() -> * もういっぱいなので coarse map に追い出して確保する場合 -> OtherRegionsTable::delete_region_table() * まだ空きがある場合 -> PosParPRT::alloc() -> PosParPRT::add_reference() -> PerRegionTable::add_reference() -> PerRegionTable::add_reference_work() -> PerRegionTable::add_card_work() -> * -> BitMap::par_at_put() * -> BitMap::at_put() -> G1RemSet::scanRS() -> G1CollectedHeap::collection_set_iterate_from() (なお使用するクロージャーは ScanRSClosure) -> ScanRSClosure::doHeapRegion() -> -> ReferenceProcessor::weak_oops_do() -> ReferenceProcessor::oops_do() (2) 処理したオブジェクトから再帰的にたどれる範囲についても全て処理する. -> G1ParEvacuateFollowersClosure::do_void() (なお使用するクロージャーは G1ParCopyClosure (ポインタ配列用は G1ParScanPartialArrayClosure)) -> G1ParScanThreadState::deal_with_reference() * 処理対象が, 処理が pending されているポインタ配列の場合: -> G1ParScanPartialArrayClosure::do_oop_nv() -> * それ以外の場合: -> G1ParCopyClosure::do_oop_nv() -> (同上) (3) (1) (1) 必要があれば concurrent mark 処理を開始させる -> ConcurrentMark::checkpointRootsInitialPost() -> G1CollectedHeap::heap_region_iterate() (なお使用するクロージャーは NoteStartOfMarkHRClosure) -> HeapRegionSeq::iterate() -> HeapRegionSeq::iterate_from() -> NoteStartOfMarkHRClosure::doHeapRegion() -> HeapRegion::note_start_of_marking() -> SATBMarkQueueSet::set_active_all_threads() -> G1CollectedHeap::set_marking_started() -> G1CollectedHeap::doConcurrentMark() -> ConcurrentMarkThread::set_started() -> Monitor::notify() (<= ここで Concurrent Mark Thread の作業を開始) VM_G1IncCollectionPause::doit_epilogue()
See: here for details
(#Under Construction)
See: here for details
(#Under Construction) See: here for details
(#Under Construction)
See: here for details
(#Under Construction)
(#Under Construction)
(#Under Construction)
(#Under Construction) See: here for details
(#Under Construction)
(#Under Construction)
(#Under Construction)
(#Under Construction)
(#Under Construction)
(#Under Construction)
(#Under Construction)
(#Under Construction)
(#Under Construction) See: here for details
(#Under Construction) See: here for details
(#Under Construction) See: here for details
(#Under Construction) See: here for details
処理の概要は以下のコメント参照. 引数で渡された OopClosure (引数名は roots) の do_oop() を全ての root に対して適用する関数.
なお, Perm 内を指しているポインタに付いては, 引数の collecting_perm_gen が false であれば見ない. この場合, 代わりに Perm 内のオブジェクトは全て live として, 引数で渡された OopsInGenClosure (引数名は perm_blk) を Perm 内の全ての (Perm 外への) 参照に対して適用する.
また, 処理対称にする root 種別は引数で選択することができる (引数名は so). 選択できる root 種別には以下のものがある.
((cite: hotspot/src/share/vm/memory/sharedHeap.hpp))
// Invoke the "do_oop" method the closure "roots" on all root locations.
// If "collecting_perm_gen" is false, then roots that may only contain
// references to permGen objects are not scanned; instead, in that case,
// the "perm_blk" closure is applied to all outgoing refs in the
// permanent generation. The "so" argument determines which of roots
// the closure is applied to:
// "SO_None" does none;
// "SO_AllClasses" applies the closure to all entries in the SystemDictionary;
// "SO_SystemClasses" to all the "system" classes and loaders;
// "SO_Strings" applies the closure to all entries in StringTable;
// "SO_CodeCache" applies the closure to all elements of the CodeCache.
See: here for details
See: here for details
See: here for details
(#Under Construction)
(#Under Construction)
((cite: hotspot/src/share/vm/gc_implementation/g1/g1OopClosures.hpp))
(1) G1ParCopyClosure::do_oop_nv() を呼び出すだけ.
virtual void do_oop(oop* p) { do_oop_nv(p); }
virtual void do_oop(narrowOop* p) { do_oop_nv(p); }
See: here for details
(#Under Construction) See: here for details
(#Under Construction) See: here for details
See: here for details
See: here for details
See: here for details
(#Under Construction) See: here for details
See: here for details
See: here for details
See: here for details
(#Under Construction)
(#Under Construction) See: here for details
See: here for details
(#Under Construction) See: here for details
(#Under Construction)
See: here for details
See: here for details
(#Under Construction) See: here for details
(#Under Construction)
See: here for details
See: here for details
See: here for details
See: here for details
See: here for details
See: here for details
See: here for details
See: here for details
See: here for details
See: here for details
See: here for details
See: here for details
See: here for details
See: here for details
See: here for details
(#Under Construction)
See: here for details
See: here for details
See: here for details
See: here for details
See: here for details
See: here for details
See: here for details
See: here for details
See: here for details
(#Under Construction) See: here for details
(#Under Construction) See: here for details
(#Under Construction) See: here for details
(#Under Construction) See: here for details
See: here for details
See: here for details
See: here for details
See: here for details
(#Under Construction)
(#Under Construction)
(#Under Construction)
(#Under Construction)
(#Under Construction) See: here for details
(#Under Construction) See: here for details
See: here for details
(#Under Construction) See: here for details
See: here for details
See: here for details
See: here for details
(#Under Construction)
(#Under Construction)
(#Under Construction)
(#Under Construction)
This document is available under the GNU GENERAL PUBLIC LICENSE Version 2.