hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp
void G1CollectedHeap::increment_full_collections_completed(bool concurrent) {
{- -------------------------------------------
(1) (この関数は Concurrent Mark Thread と
Full GC を行った VMThread から同時に呼ばれる可能性があるので,
FullGCCount_lock を取って排他しておく)
---------------------------------------- -}
MonitorLockerEx x(FullGCCount_lock, Mutex::_no_safepoint_check_flag);
{- -------------------------------------------
(1) (concurrent 引数が true であれば, 呼び出し元は Concurrent Mark Thread.
逆に false であれば, 呼び出し元は Full GC を実行した VMThread)
(呼び出し元を簡単に確認できる方法があれば assert を追加したい, とのこと)
---------------------------------------- -}
// We assume that if concurrent == true, then the caller is a
// concurrent thread that was joined the Suspendible Thread
// Set. If there's ever a cheap way to check this, we should add an
// assert here.
{- -------------------------------------------
(1) (assert)
(_full_collections_completed フィールドには以前の total_full_collections() の数を記録してある.
total_full_collections() の回数は GC 開始時にインクリメントしているので,
この時点での数字は _full_collections_completed フィールドの値より大きい.
ただし, Concurrent Mark 処理と Full GC 処理は同時に行われる可能性があるので,
1つ大きくなっているケースと 2つ大きくなっているケースが考えられる.
Concurrent Mark Thread から呼ばれた場合は,
処理中に Full GC も発生し, しかもそれがまだ終わっていなければ, 2つ増えている可能性がある.
VMThread から呼ばれた場合は, 1つ大きくなっているケースしかありえない.)
---------------------------------------- -}
// We have already incremented _total_full_collections at the start
// of the GC, so total_full_collections() represents how many full
// collections have been started.
unsigned int full_collections_started = total_full_collections();
// Given that this method is called at the end of a Full GC or of a
// concurrent cycle, and those can be nested (i.e., a Full GC can
// interrupt a concurrent cycle), the number of full collections
// completed should be either one (in the case where there was no
// nesting) or two (when a Full GC interrupted a concurrent cycle)
// behind the number of full collections started.
// This is the case for the inner caller, i.e. a Full GC.
assert(concurrent ||
(full_collections_started == _full_collections_completed + 1) ||
(full_collections_started == _full_collections_completed + 2),
err_msg("for inner caller (Full GC): full_collections_started = %u "
"is inconsistent with _full_collections_completed = %u",
full_collections_started, _full_collections_completed));
// This is the case for the outer caller, i.e. the concurrent cycle.
assert(!concurrent ||
(full_collections_started == _full_collections_completed + 1),
err_msg("for outer caller (concurrent cycle): "
"full_collections_started = %u "
"is inconsistent with _full_collections_completed = %u",
full_collections_started, _full_collections_completed));
{- -------------------------------------------
(1) _full_collections_completed フィールドをインクリメント.
(このフィールドの値は, System.gc() で Concurrent Full GC が実行された場合に,
その終了を待ち合わせるために使用される.
See: VM_G1IncCollectionPause::doit(), VM_G1IncCollectionPause::doit_epilogue())
---------------------------------------- -}
_full_collections_completed += 1;
{- -------------------------------------------
(1) Concurrent Mark Thread から呼び出された場合は,
ConcurrentMarkThread::clear_in_progress() を呼んで
in_progress フィールドをクリアしておく.
(これは, Full GC の完了を待っているスレッドが
起床後に System.gc() を呼び出すようなケースで,
Concurrent Mark が実行中だと勘違いしないようにするための措置.)
---------------------------------------- -}
// We need to clear the "in_progress" flag in the CM thread before
// we wake up any waiters (especially when ExplicitInvokesConcurrent
// is set) so that if a waiter requests another System.gc() it doesn't
// incorrectly see that a marking cyle is still in progress.
if (concurrent) {
_cmThread->clear_in_progress();
}
{- -------------------------------------------
(1) (Full GC の完了を待っているスレッドがいるかもしれないので)
FullGCCount_lock に対して Monitor::notify_all() を呼び出し,
待っているスレッドがいれば起床させておく.
(See: VM_G1IncCollectionPause::doit_epilogue())
---------------------------------------- -}
// This notify_all() will ensure that a thread that called
// System.gc() with (with ExplicitGCInvokesConcurrent set or not)
// and it's waiting for a full GC to finish will be woken up. It is
// waiting in VM_G1IncCollectionPause::doit_epilogue().
FullGCCount_lock->notify_all();
}
This document is available under the GNU GENERAL PUBLIC LICENSE Version 2.