hotspot/src/share/vm/memory/genCollectedHeap.cpp
void GenCollectedHeap::do_collection(bool full,
bool clear_all_soft_refs,
size_t size,
bool is_tlab,
int max_level) {
{- -------------------------------------------
(1) (変数宣言など)
---------------------------------------- -}
bool prepared_for_verification = false;
ResourceMark rm;
DEBUG_ONLY(Thread* my_thread = Thread::current();)
{- -------------------------------------------
(1) (assert)
---------------------------------------- -}
assert(SafepointSynchronize::is_at_safepoint(), "should be at safepoint");
assert(my_thread->is_VM_thread() ||
my_thread->is_ConcurrentGC_thread(),
"incorrect thread type capability");
assert(Heap_lock->is_locked(),
"the requesting thread should have the Heap_lock");
guarantee(!is_gc_active(), "collection is not reentrant");
assert(max_level < n_gens(), "sanity check");
{- -------------------------------------------
(1) もし GC_locker によって GC が禁止されていれば, ここでリターン.
---------------------------------------- -}
if (GC_locker::check_active_before_gc()) {
return; // GC is disabled (e.g. JNI GetXXXCritical operation)
}
{- -------------------------------------------
(1) (変数宣言など)
---------------------------------------- -}
const bool do_clear_all_soft_refs = clear_all_soft_refs ||
collector_policy()->should_clear_all_soft_refs();
ClearedAllSoftRefs casr(do_clear_all_soft_refs, collector_policy());
const size_t perm_prev_used = perm_gen()->used();
{- -------------------------------------------
(1) (トレース出力)
---------------------------------------- -}
if (PrintHeapAtGC) {
Universe::print_heap_before_gc();
if (Verbose) {
gclog_or_tty->print_cr("GC Cause: %s", GCCause::to_string(gc_cause()));
}
}
{- -------------------------------------------
(1) (以下のブロック内では _is_gc_active を true にしておく)
---------------------------------------- -}
{
FlagSetting fl(_is_gc_active, true);
{- -------------------------------------------
(1) (変数宣言など)
---------------------------------------- -}
bool complete = full && (max_level == (n_gens()-1));
const char* gc_cause_str = "GC ";
if (complete) {
GCCause::Cause cause = gc_cause();
if (cause == GCCause::_java_lang_system_gc) {
gc_cause_str = "Full GC (System) ";
} else {
gc_cause_str = "Full GC ";
}
}
{- -------------------------------------------
(1) (トレース出力)
---------------------------------------- -}
gclog_or_tty->date_stamp(PrintGC && PrintGCDateStamps);
TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty);
TraceTime t(gc_cause_str, PrintGCDetails, false, gclog_or_tty);
{- -------------------------------------------
(1) GenCollectedHeap::gc_prologue() を呼び出して, GC の前準備を行う.
---------------------------------------- -}
gc_prologue(complete);
{- -------------------------------------------
(1) GC を行うことになったので, CollectedHeap::total_collections() の値を増加させておく.
(See: CollectedHeap::total_collections())
---------------------------------------- -}
increment_total_collections(complete);
{- -------------------------------------------
(1) (変数宣言など)
(starting_level は, 最初に GC を試みる世代を表す)
---------------------------------------- -}
size_t gch_prev_used = used();
int starting_level = 0;
if (full) {
// Search for the oldest generation which will collect all younger
// generations, and start collection loop there.
for (int i = max_level; i >= 0; i--) {
if (_gens[i]->full_collects_younger_generations()) {
starting_level = i;
break;
}
}
}
bool must_restore_marks_for_biased_locking = false;
{- -------------------------------------------
(1) (以下の for ループ内で実際の GC 処理を行う.
GC は starting_level 変数が示す世代から開始し,
Generation::should_collect() が true を返す全ての Generation に対して行う)
(なお, ループ処理中に確保要求が満たせる世代ができた場合は,
その時点で size 変数が 0 にセットされる(後述)ことに注意)
---------------------------------------- -}
int max_level_collected = starting_level;
for (int i = starting_level; i <= max_level; i++) {
if (_gens[i]->should_collect(full, size, is_tlab)) {
{- -------------------------------------------
(1.1) もし Major GC を実行する場合は, CollectedHeap::pre_full_gc_dump() を呼び出しておく.
(これは保守運用機能用の関数. 関連するコマンドラインオプションの値に応じてヒープの情報を出力する)
また, インクリメントされていなければ total_full_collections をインクリメントしておく.
---------------------------------------- -}
if (i == n_gens() - 1) { // a major collection is to happen
if (!complete) {
// The full_collections increment was missed above.
increment_total_full_collections();
}
pre_full_gc_dump(); // do any pre full gc dumps
}
{- -------------------------------------------
(1.1) (トレース出力用の処理)
---------------------------------------- -}
// Timer for individual generations. Last argument is false: no CR
TraceTime t1(_gens[i]->short_name(), PrintGCDetails, false, gclog_or_tty);
TraceCollectorStats tcs(_gens[i]->counters());
{- -------------------------------------------
(1.1) (トレース出力用の処理) (DTrace のフック点) (JMM のフック点)
(See: TraceMemoryManagerStats)
---------------------------------------- -}
TraceMemoryManagerStats tmms(_gens[i]->kind(),gc_cause());
{- -------------------------------------------
(1.1) (変数宣言など)
---------------------------------------- -}
size_t prev_used = _gens[i]->used();
{- -------------------------------------------
(1.1)
---------------------------------------- -}
_gens[i]->stat_record()->invocations++;
_gens[i]->stat_record()->accumulated_time.start();
{- -------------------------------------------
(1.1) (デバッグ用の処理)
GenCollectedHeap::record_gen_tops_before_GC() を呼ぶ
(この中では, ZapUnusedHeapArea オプションが指定されていれば,
各 Generation に対してこの時点での使用量を記録する)
---------------------------------------- -}
// Must be done anew before each collection because
// a previous collection will do mangling and will
// change top of some spaces.
record_gen_tops_before_GC();
{- -------------------------------------------
(1.1) (トレース出力)
---------------------------------------- -}
if (PrintGC && Verbose) {
gclog_or_tty->print("level=%d invoke=%d size=" SIZE_FORMAT,
i,
_gens[i]->stat_record()->invocations,
size*HeapWordSize);
}
{- -------------------------------------------
(1.1) (verify)
---------------------------------------- -}
if (VerifyBeforeGC && i >= VerifyGCLevel &&
total_collections() >= VerifyGCStartAt) {
HandleMark hm; // Discard invalid handles created during verification
if (!prepared_for_verification) {
prepare_for_verify();
prepared_for_verification = true;
}
gclog_or_tty->print(" VerifyBeforeGC:");
Universe::verify(true);
}
{- -------------------------------------------
(1.1) #ifdef COMPILER2 の場合には, (これから GC を行うので) DerivedPointerTable の値をリセットしておく.
(See: DerivedPointerTable)
---------------------------------------- -}
COMPILER2_PRESENT(DerivedPointerTable::clear());
{- -------------------------------------------
(1.1) BiasedLocking::preserve_marks() を呼んで,
mark フィールドが biased pattern になっているオブジェクトのうち
現在ロックを取得されているものについては,
その mark 値を待避しておく.
(この後の GC 処理では, 生きているオブジェクトに (生きているということを示すための) 印を付ける.
この印はオブジェクトの mark フィールドに書き込まれるが,
そのままだと元の mark フィールドの値は失われてしまうので,
元の mark をどこかに待避しておいて, GC 後に書き戻してやる必要がある.)
(なお, 複数回行う必要は無いので,
must_restore_marks_for_biased_locking 変数に既に行ったかどうかを記録している.
既に行っていた場合は呼び出さない)
---------------------------------------- -}
if (!must_restore_marks_for_biased_locking &&
_gens[i]->performs_in_place_marking()) {
// We perform this mark word preservation work lazily
// because it's only at this point that we know whether we
// absolutely have to do it; we want to avoid doing it for
// scavenge-only collections where it's unnecessary
must_restore_marks_for_biased_locking = true;
BiasedLocking::preserve_marks();
}
{- -------------------------------------------
(1.1) (以下のブロック内で実際の GC 処理を行う)
---------------------------------------- -}
// Do collection work
{
{- -------------------------------------------
(1.1)
---------------------------------------- -}
// Note on ref discovery: For what appear to be historical reasons,
// GCH enables and disabled (by enqueing) refs discovery.
// In the future this should be moved into the generation's
// collect method so that ref discovery and enqueueing concerns
// are local to a generation. The collect method could return
// an appropriate indication in the case that notification on
// the ref lock was needed. This will make the treatment of
// weak refs more uniform (and indeed remove such concerns
// from GCH). XXX
{- -------------------------------------------
(1.1) (変数宣言など)
---------------------------------------- -}
HandleMark hm; // Discard invalid handles created during gc
{- -------------------------------------------
(1.1)
---------------------------------------- -}
save_marks(); // save marks for all gens
{- -------------------------------------------
(1.1) これから GC を行うので, ReferenceProcessor オブジェクトをリセットしておく.
---------------------------------------- -}
// We want to discover references, but not process them yet.
// This mode is disabled in process_discovered_references if the
// generation does some collection work, or in
// enqueue_discovered_references if the generation returns
// without doing any work.
ReferenceProcessor* rp = _gens[i]->ref_processor();
// If the discovery of ("weak") refs in this generation is
// atomic wrt other collectors in this configuration, we
// are guaranteed to have empty discovered ref lists.
if (rp->discovery_is_atomic()) {
rp->verify_no_references_recorded();
rp->enable_discovery();
rp->setup_policy(do_clear_all_soft_refs);
} else {
// collect() below will enable discovery as appropriate
}
{- -------------------------------------------
(1.1) Generation::collect() を呼んで GC を行う.
(なお, Generation::collect() は Generation クラスの各サブクラスによってオーバーライドされているため,
処理は Generation 毎に異なる)
---------------------------------------- -}
_gens[i]->collect(full, do_clear_all_soft_refs, size, is_tlab);
{- -------------------------------------------
(1.1) ReferenceProcessor::enqueue_discovered_references() で
リストに残った参照オブジェクト(= 差し先が死んだため特殊な処理が必要な参照オブジェクト)を pending list に追加する.
---------------------------------------- -}
if (!rp->enqueuing_is_done()) {
rp->enqueue_discovered_references();
} else {
rp->set_enqueuing_is_done(false);
}
rp->verify_no_references_recorded();
}
{- -------------------------------------------
(1.1) GC を実行した世代の番号を記録しておく
---------------------------------------- -}
max_level_collected = i;
{- -------------------------------------------
(1.1) 現在の Generation で確保要求が満たせるようになった場合は,
size 変数を 0 にしてしまう.
---------------------------------------- -}
// Determine if allocation request was met.
if (size > 0) {
if (!is_tlab || _gens[i]->supports_tlab_allocation()) {
if (size*HeapWordSize <= _gens[i]->unsafe_max_alloc_nogc()) {
size = 0;
}
}
}
{- -------------------------------------------
(1.1) #ifdef COMPILER2 の場合には, GC が終わったので
見つかった derived pointer の値を修正しておく.
(See: DerivedPointerTable)
---------------------------------------- -}
COMPILER2_PRESENT(DerivedPointerTable::update_pointers());
{- -------------------------------------------
(1.1) GC 終了時の時刻を記録しておく.
---------------------------------------- -}
_gens[i]->stat_record()->accumulated_time.stop();
{- -------------------------------------------
(1.1)
---------------------------------------- -}
update_gc_stats(i, full);
{- -------------------------------------------
(1.1) (verify)
---------------------------------------- -}
if (VerifyAfterGC && i >= VerifyGCLevel &&
total_collections() >= VerifyGCStartAt) {
HandleMark hm; // Discard invalid handles created during verification
gclog_or_tty->print(" VerifyAfterGC:");
Universe::verify(false);
}
{- -------------------------------------------
(1.1) (トレース出力)
---------------------------------------- -}
if (PrintGCDetails) {
gclog_or_tty->print(":");
_gens[i]->print_heap_change(prev_used);
}
}
}
{- -------------------------------------------
(1) (変数宣言など)
---------------------------------------- -}
// Update "complete" boolean wrt what actually transpired --
// for instance, a promotion failure could have led to
// a whole heap collection.
complete = complete || (max_level_collected == n_gens() - 1);
{- -------------------------------------------
(1) (保守運用機能用の処理)
Major GC を実行した場合は, CollectedHeap::post_full_gc_dump() を呼び出す.
(この中では関連するコマンドラインオプションの値に応じてヒープの情報を出力する)
---------------------------------------- -}
if (complete) { // We did a "major" collection
post_full_gc_dump(); // do any post full gc dumps
}
{- -------------------------------------------
(1) (トレース出力)
---------------------------------------- -}
if (PrintGCDetails) {
print_heap_change(gch_prev_used);
// Print perm gen info for full GC with PrintGCDetails flag.
if (complete) {
print_perm_heap_change(perm_prev_used);
}
}
{- -------------------------------------------
(1) ゴミを回収した各領域に対して Generation::compute_new_size() を呼び出し,
領域の大きさを最適に調整しておく.
---------------------------------------- -}
for (int j = max_level_collected; j >= 0; j -= 1) {
// Adjust generation sizes.
_gens[j]->compute_new_size();
}
{- -------------------------------------------
(1) Perm 領域内のゴミも回収したので,
Generation::compute_new_size() を呼んで, 大きさを最適に調整しておく.
---------------------------------------- -}
if (complete) {
// Ask the permanent generation to adjust size for full collections
perm()->compute_new_size();
update_full_collections_completed();
}
{- -------------------------------------------
(1) (プロファイル情報の記録)(JMM 用) (See: MemoryUsage)
及び (JMM のフック点) でもある (See: LowMemoryDetector)
---------------------------------------- -}
// Track memory usage and detect low memory after GC finishes
MemoryService::track_memory_usage();
{- -------------------------------------------
(1) GenCollectedHeap::gc_epilogue() を呼び出して, GC の後始末を行う
---------------------------------------- -}
gc_epilogue(complete);
{- -------------------------------------------
(1) BiasedLocking::restore_marks() を呼んで,
BiasedLocking::preserve_marks() で待避していた mark 値を
元のオブジェクトの mark フィールドに書き戻す.
---------------------------------------- -}
if (must_restore_marks_for_biased_locking) {
BiasedLocking::restore_marks();
}
}
{- -------------------------------------------
(1) (トラブルシューティング用の処理) (関連する manageable オプションが指定されている場合にのみ実行) (See: AdaptiveSizePolicyOutput)
---------------------------------------- -}
AdaptiveSizePolicy* sp = gen_policy()->size_policy();
AdaptiveSizePolicyOutput(sp, total_collections());
{- -------------------------------------------
(1) (トレース出力)
---------------------------------------- -}
if (PrintHeapAtGC) {
Universe::print_heap_after_gc();
}
{- -------------------------------------------
(1) (トレース出力)
---------------------------------------- -}
#ifdef TRACESPINNING
ParallelTaskTerminator::print_termination_counts();
#endif
{- -------------------------------------------
(1) (デバッグ用の処理)
(ExitAfterGCNum オプションの処理.
ExitAfterGCNum が指定されている場合, total_collections() が ExitAfterGCNum 回数まで達していれば, ここで HotSpot の実行を終了する)
---------------------------------------- -}
if (ExitAfterGCNum > 0 && total_collections() == ExitAfterGCNum) {
tty->print_cr("Stopping after GC #%d", ExitAfterGCNum);
vm_exit(-1);
}
}
This document is available under the GNU GENERAL PUBLIC LICENSE Version 2.