hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp
// This method contains no policy. You should probably
// be calling invoke() instead.
void PSMarkSweep::invoke_no_policy(bool clear_all_softrefs) {
{- -------------------------------------------
(1) (assert)
---------------------------------------- -}
assert(SafepointSynchronize::is_at_safepoint(), "must be at a safepoint");
assert(ref_processor() != NULL, "Sanity");
{- -------------------------------------------
(1) もし GC_locker によって GC が禁止されていれば, ここでリターン.
---------------------------------------- -}
if (GC_locker::check_active_before_gc()) {
return;
}
{- -------------------------------------------
(1) (変数宣言など)
---------------------------------------- -}
ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap();
GCCause::Cause gc_cause = heap->gc_cause();
assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity");
PSAdaptiveSizePolicy* size_policy = heap->size_policy();
// The scope of casr should end after code that can change
// CollectorPolicy::_should_clear_all_soft_refs.
ClearedAllSoftRefs casr(clear_all_softrefs, heap->collector_policy());
PSYoungGen* young_gen = heap->young_gen();
PSOldGen* old_gen = heap->old_gen();
PSPermGen* perm_gen = heap->perm_gen();
{- -------------------------------------------
(1) GC を行うことになったので, CollectedHeap::total_collections() の値を増加させておく.
(See: CollectedHeap::total_collections())
---------------------------------------- -}
// Increment the invocation count
heap->increment_total_collections(true /* full */);
{- -------------------------------------------
(1) (デバッグ用の処理)
(ZapUnusedHeapArea オプションが指定されている場合は GC 後にゴミになった領域を明示的に破壊するが,
その際に少しでも処理時間が短くなるよう, GC 開始時点でどこまで使っていたかを記録しておく処理.
(GC 開始時点で未使用だった領域は既に破壊されているので改めて破壊し直す必要は無いため))
---------------------------------------- -}
// Save information needed to minimize mangling
heap->record_gen_tops_before_GC();
{- -------------------------------------------
(1) GC を行うことになったので, PSMarkSweep::_total_invocations の値を増加させておく.
(See: PSMarkSweep::total_invocations())
---------------------------------------- -}
// We need to track unique mark sweep invocations as well.
_total_invocations++;
{- -------------------------------------------
(1) (トレース出力) (See: AdaptiveSizePolicyOutput)
---------------------------------------- -}
AdaptiveSizePolicyOutput(size_policy, heap->total_collections());
{- -------------------------------------------
(1) (トレース出力)
---------------------------------------- -}
if (PrintHeapAtGC) {
Universe::print_heap_before_gc();
}
{- -------------------------------------------
(1) ParallelScavengeHeap::accumulate_statistics_all_tlabs() で,
TLAB 関係の統計情報を更新しておく.
---------------------------------------- -}
// Fill in TLABs
heap->accumulate_statistics_all_tlabs();
{- -------------------------------------------
(1) GC 処理の前に ParallelScavengeHeap::ensure_parsability() を呼んで,
各 TLAB に残っている未使用領域を埋めて
オブジェクトでひとつながりの状態にしておく (GC アルゴリズムを簡単にするため).
---------------------------------------- -}
heap->ensure_parsability(true); // retire TLABs
{- -------------------------------------------
(1) (verify)
---------------------------------------- -}
if (VerifyBeforeGC && heap->total_collections() >= VerifyGCStartAt) {
HandleMark hm; // Discard invalid handles created during verification
gclog_or_tty->print(" VerifyBeforeGC:");
Universe::verify(true);
}
{- -------------------------------------------
(1) (verify)
---------------------------------------- -}
// Verify object start arrays
if (VerifyObjectStartArray &&
VerifyBeforeGC) {
old_gen->verify_object_start_array();
perm_gen->verify_object_start_array();
}
{- -------------------------------------------
(1) (トレース出力)
(See: CollectedHeap::pre_full_gc_dump())
---------------------------------------- -}
heap->pre_full_gc_dump();
{- -------------------------------------------
(1) (変数宣言など)
---------------------------------------- -}
// Filled in below to track the state of the young gen after the collection.
bool eden_empty;
bool survivors_empty;
bool young_gen_empty;
{
HandleMark hm;
{- -------------------------------------------
(1) (トレース出力用の処理) & (トレース出力)
---------------------------------------- -}
const bool is_system_gc = gc_cause == GCCause::_java_lang_system_gc;
// This is useful for debugging but don't change the output the
// the customer sees.
const char* gc_cause_str = "Full GC";
if (is_system_gc && PrintGCDetails) {
gc_cause_str = "Full GC (System)";
}
gclog_or_tty->date_stamp(PrintGC && PrintGCDateStamps);
TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty);
TraceTime t1(gc_cause_str, PrintGC, !PrintGCDetails, gclog_or_tty);
TraceCollectorStats tcs(counters());
{- -------------------------------------------
(1) (トレース出力用の処理) (DTrace のフック点) (JMM のフック点)
(See: TraceMemoryManagerStats)
---------------------------------------- -}
TraceMemoryManagerStats tms(true /* Full GC */,gc_cause);
{- -------------------------------------------
(1) (トレース出力用の処理)
(Old 領域の GC にかかる時間を記録)
---------------------------------------- -}
if (TraceGen1Time) accumulated_time()->start();
{- -------------------------------------------
(1) AdaptiveSizePolicy を更新する
(ここから先が GC 処理の時間になるので,
AdaptiveSizePolicy::major_collection_begin() を呼んで
PSAdaptiveSizePolicy オブジェクト内の非GC時間情報を更新)
---------------------------------------- -}
// Let the size policy know we're starting
size_policy->major_collection_begin();
{- -------------------------------------------
(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) BiasedLocking::preserve_marks() を呼んで,
mark フィールドが biased pattern になっているオブジェクトのうち
現在ロックを取得されているものについては,
その mark 値を待避しておく.
(この後の GC 処理では, 生きているオブジェクトに (生きているということを示すための) 印を付ける.
この印はオブジェクトの mark フィールドに書き込まれるが,
そのままだと元の mark フィールドの値は失われてしまうので,
元の mark をどこかに待避しておいて, GC 後に書き戻してやる必要がある.)
---------------------------------------- -}
BiasedLocking::preserve_marks();
{- -------------------------------------------
(1) (変数宣言など)
---------------------------------------- -}
// Capture heap size before collection for printing.
size_t prev_used = heap->used();
// Capture perm gen size before collection for sizing.
size_t perm_gen_prev_used = perm_gen->used_in_bytes();
// For PrintGCDetails
size_t old_gen_prev_used = old_gen->used_in_bytes();
size_t young_gen_prev_used = young_gen->used_in_bytes();
{- -------------------------------------------
(1) PSMarkSweep::allocate_stacks() で, mark フィールドの値を待避するための領域を確保しておく.
(See: PreservedMark)
---------------------------------------- -}
allocate_stacks();
{- -------------------------------------------
(1) (verify)
---------------------------------------- -}
NOT_PRODUCT(ref_processor()->verify_no_references_recorded());
{- -------------------------------------------
(1) #ifdef COMPILER2 の場合には, (これから GC を行うので) DerivedPointerTable の値をリセットしておく.
(See: DerivedPointerTable)
---------------------------------------- -}
COMPILER2_PRESENT(DerivedPointerTable::clear());
{- -------------------------------------------
(1) これから GC を行うので, ReferenceProcessor オブジェクトをリセットしておく.
---------------------------------------- -}
ref_processor()->enable_discovery();
ref_processor()->setup_policy(clear_all_softrefs);
{- -------------------------------------------
(1) PSMarkSweep::mark_sweep_phase1() を呼んで,
全ての生きているオブジェクト(live object)にマークを付ける.
---------------------------------------- -}
mark_sweep_phase1(clear_all_softrefs);
{- -------------------------------------------
(1) PSMarkSweep::mark_sweep_phase2() を呼んで,
各 live object に対して, コンパクション後の新しいアドレスを forwarding pointer として埋め込む.
---------------------------------------- -}
mark_sweep_phase2();
{- -------------------------------------------
(1) #ifdef COMPILER2 の場合, DerivedPointerTable::set_active() を呼んで,
DerivedPointerTable にこれ以上ポインタが登録されないようにしておく.
---------------------------------------- -}
// Don't add any more derived pointers during phase3
COMPILER2_PRESENT(assert(DerivedPointerTable::is_active(), "Sanity"));
COMPILER2_PRESENT(DerivedPointerTable::set_active(false));
{- -------------------------------------------
(1) PSMarkSweep::mark_sweep_phase3() を呼んで, 各 live object 内のポインタを新しいアドレスに修正する.
---------------------------------------- -}
mark_sweep_phase3();
{- -------------------------------------------
(1) PSMarkSweep::mark_sweep_phase4() を呼んで, 各 live object を新しいアドレスに移動させる.
---------------------------------------- -}
mark_sweep_phase4();
{- -------------------------------------------
(1) MarkSweep::restore_marks() を呼んで,
MarkSweep::preserve_mark() で待避していた mark 値を
元のオブジェクトの mark フィールドに書き戻す.
(See: PreservedMark)
---------------------------------------- -}
restore_marks();
{- -------------------------------------------
(1) PSMarkSweep::deallocate_stacks() で,
PSMarkSweep::allocate_stacks() で設定した PreservedMark 用の領域を解放する.
(See: PreservedMark)
(ついでに marking stack や revisit_klass_stack 等もクリアしている模様 #TODO)
---------------------------------------- -}
deallocate_stacks();
{- -------------------------------------------
(1) (デバッグ用の処理)
(ZapUnusedHeapArea オプションが指定されている場合は ...#TODO)
---------------------------------------- -}
if (ZapUnusedHeapArea) {
// Do a complete mangle (top to end) because the usage for
// scratch does not maintain a top pointer.
young_gen->to_space()->mangle_unused_area_complete();
}
{- -------------------------------------------
(1) もし GC 後にも Eden 領域内にオブジェクトが残っていた場合,
PSMarkSweep::absorb_live_data_from_eden() を呼んで,
領域間の境界をずらすことで, それらを Old 領域内へと移動させることを試みる.
(成功したかどうかが, 以下の eden_empty に格納される)
---------------------------------------- -}
eden_empty = young_gen->eden_space()->is_empty();
if (!eden_empty) {
eden_empty = absorb_live_data_from_eden(size_policy, young_gen, old_gen);
}
{- -------------------------------------------
(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) (変数宣言など)
---------------------------------------- -}
survivors_empty = young_gen->from_space()->is_empty() &&
young_gen->to_space()->is_empty();
young_gen_empty = eden_empty && survivors_empty;
{- -------------------------------------------
(1) もし barrier set として ModRefBarrierSet (もしくはそのサブクラス) を使用している場合,
Perm 領域及び Old 領域に対応する barrier set の値を変更しておく.
* もう New 領域内にオブジェクトがない場合 (以下の young_gen_empty が true):
ModRefBarrierSet::clear() で, 対応する箇所全てをクリアする.
* まだ New 領域内にオブジェクトがある場合 (以下の young_gen_empty が false):
ModRefBarrierSet::invalidate() で, 対応する箇所全てを dirty にする.
---------------------------------------- -}
BarrierSet* bs = heap->barrier_set();
if (bs->is_a(BarrierSet::ModRef)) {
ModRefBarrierSet* modBS = (ModRefBarrierSet*)bs;
MemRegion old_mr = heap->old_gen()->reserved();
MemRegion perm_mr = heap->perm_gen()->reserved();
assert(perm_mr.end() <= old_mr.start(), "Generations out of order");
if (young_gen_empty) {
modBS->clear(MemRegion(perm_mr.start(), old_mr.end()));
} else {
modBS->invalidate(MemRegion(perm_mr.start(), old_mr.end()));
}
}
{- -------------------------------------------
(1) BiasedLocking::restore_marks() を呼んで,
BiasedLocking::preserve_marks() で待避していた mark 値を
元のオブジェクトの mark フィールドに書き戻す.
---------------------------------------- -}
BiasedLocking::restore_marks();
{- -------------------------------------------
(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) #ifdef COMPILER2 の場合には, GC が終わったので
見つかった derived pointer の値を修正しておく.
(See: DerivedPointerTable)
---------------------------------------- -}
COMPILER2_PRESENT(DerivedPointerTable::update_pointers());
{- -------------------------------------------
(1) 参照オブジェクト(java.lang.ref オブジェクト)に対する後始末を行う.
(ReferenceProcessor::enqueue_discovered_references() で
リストに残った参照オブジェクト(= 差し先が死んだため特殊な処理が必要な参照オブジェクト)を pending list に追加する)
---------------------------------------- -}
ref_processor()->enqueue_discovered_references(NULL);
{- -------------------------------------------
(1) PSMarkSweep::reset_millis_since_last_gc() で, _time_of_last_gc フィールドを現在時刻に更新しておく.
(これは sun.misc.GC.maxObjectInspectionAge() メソッドを実現するため(だけ)の処理.
See: JVM_MaxObjectInspectionAge())
---------------------------------------- -}
// Update time of last GC
reset_millis_since_last_gc();
{- -------------------------------------------
(1) AdaptiveSizePolicy を更新する
(ここまでが GC 処理の時間になるので,
AdaptiveSizePolicy::major_collection_end() を呼んで,
PSAdaptiveSizePolicy オブジェクト内の GC 時間情報を更新する)
---------------------------------------- -}
// Let the size policy know we're done
size_policy->major_collection_end(old_gen->used_in_bytes(), gc_cause);
{- -------------------------------------------
(1) GC 結果に基づいて領域長を調整しておく.
(See: GC Ergonomics)
---------------------------------------- -}
if (UseAdaptiveSizePolicy) {
if (PrintAdaptiveSizePolicy) {
gclog_or_tty->print("AdaptiveSizeStart: ");
gclog_or_tty->stamp();
gclog_or_tty->print_cr(" collection: %d ",
heap->total_collections());
if (Verbose) {
gclog_or_tty->print("old_gen_capacity: %d young_gen_capacity: %d"
" perm_gen_capacity: %d ",
old_gen->capacity_in_bytes(), young_gen->capacity_in_bytes(),
perm_gen->capacity_in_bytes());
}
}
// Don't check if the size_policy is ready here. Let
// the size_policy check that internally.
if (UseAdaptiveGenerationSizePolicyAtMajorCollection &&
((gc_cause != GCCause::_java_lang_system_gc) ||
UseAdaptiveSizePolicyWithSystemGC)) {
// Calculate optimal free space amounts
assert(young_gen->max_size() >
young_gen->from_space()->capacity_in_bytes() +
young_gen->to_space()->capacity_in_bytes(),
"Sizes of space in young gen are out-of-bounds");
size_t max_eden_size = young_gen->max_size() -
young_gen->from_space()->capacity_in_bytes() -
young_gen->to_space()->capacity_in_bytes();
size_policy->compute_generation_free_space(young_gen->used_in_bytes(),
young_gen->eden_space()->used_in_bytes(),
old_gen->used_in_bytes(),
perm_gen->used_in_bytes(),
young_gen->eden_space()->capacity_in_bytes(),
old_gen->max_gen_size(),
max_eden_size,
true /* full gc*/,
gc_cause,
heap->collector_policy());
heap->resize_old_gen(size_policy->calculated_old_free_size_in_bytes());
// Don't resize the young generation at an major collection. A
// desired young generation size may have been calculated but
// resizing the young generation complicates the code because the
// resizing of the old generation may have moved the boundary
// between the young generation and the old generation. Let the
// young generation resizing happen at the minor collections.
}
if (PrintAdaptiveSizePolicy) {
gclog_or_tty->print_cr("AdaptiveSizeStop: collection: %d ",
heap->total_collections());
}
}
{- -------------------------------------------
(1) (プロファイル情報の記録) (See: PSGCAdaptivePolicyCounters)
---------------------------------------- -}
if (UsePerfData) {
heap->gc_policy_counters()->update_counters();
heap->gc_policy_counters()->update_old_capacity(
old_gen->capacity_in_bytes());
heap->gc_policy_counters()->update_young_capacity(
young_gen->capacity_in_bytes());
}
{- -------------------------------------------
(1) ParallelScavengeHeap::resize_all_tlabs() で, 各スレッドの TLAB の大きさを最適に調整しておく.
---------------------------------------- -}
heap->resize_all_tlabs();
{- -------------------------------------------
(1) Perm 領域内のゴミも回収したので,
PSPermGen::compute_new_size() を呼んで, 大きさを最適に調整しておく.
---------------------------------------- -}
// We collected the perm gen, so we'll resize it here.
perm_gen->compute_new_size(perm_gen_prev_used);
{- -------------------------------------------
(1) (トレース出力用の処理)
(Old 領域の GC にかかる時間を記録)
---------------------------------------- -}
if (TraceGen1Time) accumulated_time()->stop();
{- -------------------------------------------
(1) (トレース出力)
---------------------------------------- -}
if (PrintGC) {
if (PrintGCDetails) {
// Don't print a GC timestamp here. This is after the GC so
// would be confusing.
young_gen->print_used_change(young_gen_prev_used);
old_gen->print_used_change(old_gen_prev_used);
}
heap->print_heap_change(prev_used);
// Do perm gen after heap becase prev_used does
// not include the perm gen (done this way in the other
// collectors).
if (PrintGCDetails) {
perm_gen->print_used_change(perm_gen_prev_used);
}
}
{- -------------------------------------------
(1) (プロファイル情報の記録)(JMM 用) (See: MemoryUsage)
及び (JMM のフック点) でもある (See: LowMemoryDetector)
---------------------------------------- -}
// Track memory usage and detect low memory
MemoryService::track_memory_usage();
{- -------------------------------------------
(1) ParallelScavengeHeap::update_counters()を呼んで, (プロファイル情報の記録)を行う.
(See: SpaceCounter, PSGenerationCounters)
---------------------------------------- -}
heap->update_counters();
}
{- -------------------------------------------
(1) (verify)
---------------------------------------- -}
if (VerifyAfterGC && heap->total_collections() >= VerifyGCStartAt) {
HandleMark hm; // Discard invalid handles created during verification
gclog_or_tty->print(" VerifyAfterGC:");
Universe::verify(false);
}
{- -------------------------------------------
(1) (verify)
---------------------------------------- -}
// Re-verify object start arrays
if (VerifyObjectStartArray &&
VerifyAfterGC) {
old_gen->verify_object_start_array();
perm_gen->verify_object_start_array();
}
{- -------------------------------------------
(1) (デバッグ用の処理)
(ZapUnusedHeapArea オプションが指定されている場合は ...#TODO)
---------------------------------------- -}
if (ZapUnusedHeapArea) {
old_gen->object_space()->check_mangled_unused_area_complete();
perm_gen->object_space()->check_mangled_unused_area_complete();
}
{- -------------------------------------------
(1) (verify)
---------------------------------------- -}
NOT_PRODUCT(ref_processor()->verify_no_references_recorded());
{- -------------------------------------------
(1) (トレース出力)
---------------------------------------- -}
if (PrintHeapAtGC) {
Universe::print_heap_after_gc();
}
{- -------------------------------------------
(1) (トレース出力)
(See: CollectedHeap::post_full_gc_dump())
---------------------------------------- -}
heap->post_full_gc_dump();
{- -------------------------------------------
(1) (トレース出力)
---------------------------------------- -}
#ifdef TRACESPINNING
ParallelTaskTerminator::print_termination_counts();
#endif
}
This document is available under the GNU GENERAL PUBLIC LICENSE Version 2.