調整可能であるように見えますが、そうではありません。同時マークスイープコレクターは、デフォルトのヒープの実装でハングします。デフォルトのヒープの実装はmust_clear_all_soft_refs()
、明らかに。true
を実行する場合のみ_last_ditch_collection
です。
bool GenCollectedHeap::must_clear_all_soft_refs() {
return _gc_cause == GCCause::_last_ditch_collection;
}
失敗した割り当ての通常の処理では、ヒープのdo_collect
メソッドが3回連続して呼び出されますが、CollectorPolicy.cpp
HeapWord* GenCollectorPolicy::satisfy_failed_allocation(size_t size,
bool is_tlab) {
これは、収集を試み、再割り当てを試み、失敗した場合はヒープを拡張しようとし、最後の努力として、クリアリングソフト参照を収集しようとします。
最後のコレクションに関するコメントは非常にわかりやすいものです(そして、ソフト参照のクリアをトリガーする唯一のコレクションです)
// If we reach this point, we're really out of memory. Try every trick
// we can to reclaim memory. Force collection of soft references. Force
// a complete compaction of the heap. Any additional methods for finding
// free memory should be here, especially if they are expensive. If this
// attempt fails, an OOM exception will be thrown.
{
IntFlagSetting flag_change(MarkSweepAlwaysCompactCount, 1); // Make sure the heap is fully compacted
gch->do_collection(true /* full */,
true /* clear_all_soft_refs */,
size /* size */,
is_tlab /* is_tlab */,
number_of_generations() - 1 /* max_level */);
}
---明らかなことに応じて編集されましたが、ソフト参照ではなく弱参照を記述していました---
実際には、SoftReferencesは、JVMがガベージコレクションを回避しようとしたときに、ガベージコレクションが呼び出された場合にのみ「フォローされない」と思いOutOfMemoryError
ます。
SoftReference
sが4つのJava1.4ガベージコレクターすべて、および新しいG1コレクターと互換性を持つためには、到達可能性の決定のみに基づいて決定する必要があります。刈り取りと圧縮が行われるまでに、オブジェクトが到達可能かどうかを判断するには遅すぎます。これは、ヒープ内の空きメモリの可用性に基づいて到達可能性を決定するコレクション「コンテキスト」が存在することを示唆しています(ただし、必須ではありません)。このようなコンテキストは、SoftReference
sをフォローしようとする前に、sをフォローしていないことを示す必要があります。
OutOfMemoryError
回避ガベージコレクションは、フルコレクションのストップザワールド方式で特別にスケジュールされているため、ヒープマネージャーがコレクションが発生する前に「フォローしない」フラグを設定するシナリオを想像するのは難しいことではありませんSoftReference
。
---わかりました、それで私は「このように働かなければならない」という答えは十分ではないと判断しました---
ソースコードからsrc/share / vm / gc_implementation / concurrentMarkSweep / vmCMSOperations.cpp(ハイライトは私のものです)
ガベージコレクションを実際に「実行」する操作:
170 void VM_GenCollectFullConcurrent::doit() {
VMスレッドである方がよいです。そうでない場合、「プログラム」スレッドはガベージコレクションになります。
171 assert(Thread::current()->is_VM_thread(), "Should be VM thread");
私たちはコンカレントコレクターなので、同時にスケジュールすることをお勧めします。
172 assert(GCLockerInvokesConcurrent || ExplicitGCInvokesConcurrent, "Unexpected");
173
ヒープ(GCCauseオブジェクトが含まれている)を取得します。
174 GenCollectedHeap* gch = GenCollectedHeap::heap();
フォアグラウンドの「若い」コレクションが必要かどうかを確認します
175 if (_gc_count_before == gch->total_collections()) {
176 // The "full" of do_full_collection call below "forces"
177 // a collection; the second arg, 0, below ensures that
178 // only the young gen is collected. XXX In the future,
179 // we'll probably need to have something in this interface
180 // to say do this only if we are sure we will not bail
181 // out to a full collection in this attempt, but that's
182 // for the future.
プログラムスレッドがヒープに干渉していませんか?
183 assert(SafepointSynchronize::is_at_safepoint(),
184 "We can only be executing this arm of if at a safepoint");
ガベージコレクションの原因(このコレクションの理由)をヒープから取得します。
185 GCCauseSetter gccs(gch, _gc_cause);
若いスペースの完全なコレクションを行う
ヒープのmust_clear_all_soft_refsフラグの値を渡すことに注意してください。これは、OutOfMemoryシナリオではtrueに設定されている必要があり、いずれの場合も、「do_full_collection」にソフト参照に従わないように指示します。
186 gch->do_full_collection(gch->must_clear_all_soft_refs(),
187 0 /* collect only youngest gen */);
_gc_causeは列挙型であり、(ここでは推測で)_allocation_failure
回避の最初の試みで設定され、OutOfMemoryError
その後_last_ditch_collection
は失敗します(一時的なガベージの収集を試みます)
メモリの「ヒープ」モジュールをざっと見てみると、do_full_collection
どの呼び出しでdo_collection
ソフト参照が次の行で明示的に(「正しい」条件の下で)クリアされていることがわかります。
480 ClearedAllSoftRefs casr(do_clear_all_soft_refs, collector_policy());
---弱参照について学びたい人のために元の投稿が続きます---
マークアンドスイープアルゴリズムでは、ソフト参照はメインスレッドから追跡されません(したがって、別のブランチが非ソフト参照を介して到達できない限り、マークされません。
コピーアルゴリズムでは、オブジェクトのソフト参照が指しているものはコピーされません(別の非ソフト参照が到達しない限り)。
基本的に、実行の「メイン」スレッドから参照のWebをたどる場合、ソフト参照はたどられません。これにより、オブジェクトを指す参照がないかのように、オブジェクトをガベージコレクションできます。
ソフト参照が単独で使用されることはほとんどないことに注意することが重要です。これらは通常、デザインでオブジェクトへの複数の参照を持つオブジェクトで使用されますが、ガベージコレクションをトリガーするためにクリアする必要がある参照は1つだけです(コンテナーの保守を容易にするため、または高価な参照を検索する必要がない実行時のパフォーマンスのため) 。