hotspot/src/share/vm/memory/genMarkSweep.cpp
void GenMarkSweep::invoke_at_safepoint(int level, ReferenceProcessor* rp,
bool clear_all_softrefs) {
{- -------------------------------------------
(1) (assert)
---------------------------------------- -}
assert(SafepointSynchronize::is_at_safepoint(), "must be at a safepoint");
{- -------------------------------------------
(1) (変数宣言など)
---------------------------------------- -}
GenCollectedHeap* gch = GenCollectedHeap::heap();
{- -------------------------------------------
(1) (デバッグ用の処理) (#ifdef ASSERT 時にのみ実行)
---------------------------------------- -}
#ifdef ASSERT
if (gch->collector_policy()->should_clear_all_soft_refs()) {
assert(clear_all_softrefs, "Policy should have been checked earlier");
}
#endif
{- -------------------------------------------
(1) (assert)
---------------------------------------- -}
// hook up weak ref data so it can be used during Mark-Sweep
assert(ref_processor() == NULL, "no stomping");
assert(rp != NULL, "should be non-NULL");
{- -------------------------------------------
(1) rp 引数で渡された ReferenceProcessor を GenMarkSweep::_ref_processor フィールドに格納し,
ついでに ReferenceProcessor::setup_policy() を呼んで初期化もしておく.
---------------------------------------- -}
_ref_processor = rp;
rp->setup_policy(clear_all_softrefs);
{- -------------------------------------------
(1) (トレース出力)
---------------------------------------- -}
TraceTime t1("Full GC", PrintGC && !PrintGCDetails, true, gclog_or_tty);
{- -------------------------------------------
(1) フレーム中の bcp (byte code pointer, バイトコードを指すポインタ) を格納している箇所については
GC によって methodOop が移動すると値が不正になってしまうので,
Threads::gc_prologue() を呼んで
フレーム中の bcp を bci (byte code index, そのバイトコードのメソッド先頭からのオフセット値) に変えておく.
(なお, CodeCache::gc_prologue()の方は, 単なる(assert) (See: CodeCache::gc_prologue()))
---------------------------------------- -}
// When collecting the permanent generation methodOops may be moving,
// so we either have to flush all bcp data or convert it into bci.
CodeCache::gc_prologue();
Threads::gc_prologue();
{- -------------------------------------------
(1)
---------------------------------------- -}
// Increment the invocation count for the permanent generation, since it is
// implicitly collected whenever we do a full mark sweep collection.
gch->perm_gen()->stat_record()->invocations++;
{- -------------------------------------------
(1) (変数宣言など)
---------------------------------------- -}
// Capture heap size before collection for printing.
size_t gch_prev_used = gch->used();
{- -------------------------------------------
(1) (assert)
---------------------------------------- -}
// Some of the card table updates below assume that the perm gen is
// also being collected.
assert(level == gch->n_gens() - 1,
"All generations are being collected, ergo perm gen too.");
{- -------------------------------------------
(1)
---------------------------------------- -}
// Capture used regions for each generation that will be
// subject to collection, so that card table adjustments can
// be made intelligently (see clear / invalidate further below).
gch->save_used_regions(level, true /* perm */);
{- -------------------------------------------
(1) GenMarkSweep::allocate_stacks() を呼んで, mark フィールドの値を待避するための領域を確保しておく.
(See: PreservedMark)
---------------------------------------- -}
allocate_stacks();
{- -------------------------------------------
(1) GenMarkSweep::mark_sweep_phase1() を呼んで,
全ての生きているオブジェクト(live object)にマークを付ける.
---------------------------------------- -}
mark_sweep_phase1(level, clear_all_softrefs);
{- -------------------------------------------
(1) GenMarkSweep::mark_sweep_phase2() を呼んで,
各 live object に対して, コンパクション後の新しいアドレスを forwarding pointer として埋め込む.
---------------------------------------- -}
mark_sweep_phase2();
{- -------------------------------------------
(1) #ifdef COMPILER2 の場合には, (これから GC を行うので) DerivedPointerTable の値をリセットしておく.
(See: DerivedPointerTable)
---------------------------------------- -}
// Don't add any more derived pointers during phase3
COMPILER2_PRESENT(assert(DerivedPointerTable::is_active(), "Sanity"));
COMPILER2_PRESENT(DerivedPointerTable::set_active(false));
{- -------------------------------------------
(1) GenMarkSweep::mark_sweep_phase3() を呼んで, 各 live object 内のポインタを新しいアドレスに修正する.
---------------------------------------- -}
mark_sweep_phase3(level);
{- -------------------------------------------
(1) (assert)
---------------------------------------- -}
VALIDATE_MARK_SWEEP_ONLY(
if (ValidateMarkSweep) {
guarantee(_root_refs_stack->length() == 0, "should be empty by now");
}
)
{- -------------------------------------------
(1) GenMarkSweep::mark_sweep_phase4() を呼んで, 各 live object を新しいアドレスに移動させる.
---------------------------------------- -}
mark_sweep_phase4();
{- -------------------------------------------
(1) (assert)
---------------------------------------- -}
VALIDATE_MARK_SWEEP_ONLY(
if (ValidateMarkSweep) {
guarantee(_live_oops->length() == _live_oops_moved_to->length(),
"should be the same size");
}
)
{- -------------------------------------------
(1) MarkSweep::restore_marks() を呼んで,
MarkSweep::preserve_mark() で待避していた mark 値を, 元のオブジェクトの mark フィールドに書き戻す.
(See: PreservedMark)
---------------------------------------- -}
restore_marks();
{- -------------------------------------------
(1)
---------------------------------------- -}
// Set saved marks for allocation profiler (and other things? -- dld)
// (Should this be in general part?)
gch->save_marks();
{- -------------------------------------------
(1) GenMarkSweep::deallocate_stacks() を呼んで,
GenMarkSweep::allocate_stacks() で確保した領域を解放する.
(See: PreservedMark)
---------------------------------------- -}
deallocate_stacks();
{- -------------------------------------------
(1)
---------------------------------------- -}
// If compaction completely evacuated all generations younger than this
// one, then we can clear the card table. Otherwise, we must invalidate
// it (consider all cards dirty). In the future, we might consider doing
// compaction within generations only, and doing card-table sliding.
{- -------------------------------------------
(1.1) (変数宣言など)
---------------------------------------- -}
bool all_empty = true;
for (int i = 0; all_empty && i < level; i++) {
Generation* g = gch->get_gen(i);
all_empty = all_empty && gch->get_gen(i)->used() == 0;
}
GenRemSet* rs = gch->rem_set();
{- -------------------------------------------
(1.1)
---------------------------------------- -}
// Clear/invalidate below make use of the "prev_used_regions" saved earlier.
if (all_empty) {
// We've evacuated all generations below us.
Generation* g = gch->get_gen(level);
rs->clear_into_younger(g, true /* perm */);
} else {
// Invalidate the cards corresponding to the currently used
// region and clear those corresponding to the evacuated region
// of all generations just collected (i.e. level and younger).
rs->invalidate_or_clear(gch->get_gen(level),
true /* younger */,
true /* perm */);
}
{- -------------------------------------------
(1) フレーム中の bcp (byte code pointer, バイトコードを指すポインタ) を格納している箇所については
GC 前に Threads::gc_prologue() で
bcp から bci(byte code index, そのバイトコードのメソッド先頭からのオフセット値) へと値を変更していたので,
Threads::gc_epilogue() を呼んで元に戻しておく.
(ついでに, フレーム内の値について環境依存(プラットフォーム依存)な処理が必要であれば, それも行っている)
---------------------------------------- -}
Threads::gc_epilogue();
{- -------------------------------------------
(1) #TODO
---------------------------------------- -}
CodeCache::gc_epilogue();
{- -------------------------------------------
(1) JvmtiExport::gc_epilogue() を呼んで,
JvmtiBreakpointCache 内でキャッシュしているブレークポイントを指すポインタも更新しておく.
---------------------------------------- -}
JvmtiExport::gc_epilogue();
{- -------------------------------------------
(1) (トレース出力)
---------------------------------------- -}
if (PrintGC && !PrintGCDetails) {
gch->print_heap_change(gch_prev_used);
}
{- -------------------------------------------
(1)
---------------------------------------- -}
// refs processing: clean slate
_ref_processor = NULL;
{- -------------------------------------------
(1) Universe::update_heap_info_at_gc() を呼んで,
以下の値を現在のヒープの最大長(capacity)及び使用量(used)に応じた値に変更する.
* Universe::get_heap_capacity_at_last_gc()
* Universe::get_heap_free_at_last_gc()
* Universe::get_heap_used_at_last_gc()
なお, これらの値は ReferencePolicy オブジェクト内で soft reference の消去ポリシーの決定に使用されている.
(See: ReferencePolicy)
---------------------------------------- -}
// Update heap occupancy information which is used as
// input to soft ref clearing policy at the next gc.
Universe::update_heap_info_at_gc();
{- -------------------------------------------
(1) GenCollectedHeap::update_time_of_last_gc() を呼び出して,
全ての Generation の _time_of_last_gc フィールドを現在時刻に更新しておく.
(これは sun.misc.GC.maxObjectInspectionAge() メソッドを実現するため(だけ)の処理.
See: JVM_MaxObjectInspectionAge())
---------------------------------------- -}
// Update time of last gc for all generations we collected
// (which curently is all the generations in the heap).
gch->update_time_of_last_gc(os::javaTimeMillis());
}
This document is available under the GNU GENERAL PUBLIC LICENSE Version 2.