Java には、StrongReference、SoftReference、WeakReference、PhantomReference (伝説のゴースト参照 笑) の 4 種類の参照があります。
これら 4 種類の参照は GC と密接に関連しています。その定義と使用シナリオを 1 つずつ見てみましょう。
1. 強力な参照
StrongReference は Java のデフォルトの参照実装であり、オブジェクトがそれを指さない場合は、GC 実行後にリサイクルされます。
Javaコード
次のようにコードをコピーします。
@テスト
public void StrongReference() {
オブジェクト参照 = new Object();
/**
* 割り当てを通じて StrongReference を作成する
*/
オブジェクトstrongReference = 参照対象;
assertSame(参照元、strongReference);
参照先 = null;
System.gc();
/**
* StrongReference は GC 後にリサイクルされません
*/
assertNotNull(strongReference);
}
2.WeakReferenceとWeakHashMap
WeakReference は、その名前が示すように、弱参照です。参照されたオブジェクトが JVM 内で強参照を持たなくなった場合、弱参照は GC 後に自動的にリサイクルされます。
次のようにコードをコピーします。
@テスト
public voidweakReference() {
オブジェクト参照 = new Object();
WeakReference<Object>weakRerference = new WeakReference<Object>(参照先);
assertSame(参照、weakRerference.get());
参照先 = null;
System.gc();
/**
* 参照対象を指す強参照がなくなると、GC 後に弱参照が自動的にリサイクルされます。
*/
assertNll(weakRerference.get());
}
WeakHashMap は WeakReference をキーとして使用します。キーへの強い参照がなくなると、WeakHashMap は GC 後に関連するエントリを自動的に削除します。
次のようにコードをコピーします。
@テスト
public voidweakHashMap() は InterruptedException をスローします {
Map<オブジェクト, オブジェクト>weakHashMap = new WeakHashMap<オブジェクト, オブジェクト>();
オブジェクトキー = new Object();
オブジェクト値 = 新しい Object();
weakHashMap.put(キー, 値);
assertTrue(weakHashMap.containsValue(値));
キー = null;
System.gc();
/**
* 次回 getTable が呼び出されたときにクリアできるように、無効なエントリが ReferenceQueue に入るのを待ちます。
*/
Thread.sleep(1000);
/**
* キーへの強い参照がなくなると、WeakHashMap は GC 後に関連するエントリを自動的に削除します
*/
assertFalse(weakHashMap.containsValue(値));
}
3.ソフトリファレンス
SoftReference は基本的に WeakReference と同じ特性を持っています。最大の違いは、SoftReference がリサイクルされる前に JVM がメモリを使い果たすまで可能な限り参照を保持することです (仮想マシンの保証)。この機能により、SoftReference はキャッシュ アプリケーションに非常に適しています。
次のようにコードをコピーします。
@テスト
public void SoftReference() {
オブジェクト参照 = new Object();
SoftReference<Object> SoftRerference = new SoftReference<Object>(参照先);
assertNotNull(softRerference.get());
参照先 = null;
System.gc();
/**
* ソフト参照は jvm OutOfMemory の前にのみリサイクルされるため、アプリケーションのキャッシュに非常に適しています
*/
assertNotNull(softRerference.get());
}
4.ファントムリファレンス
この記事の主役である Phantom Reference は、WeakReference や SoftReference とは大きく異なります。その理由は、その get() メソッドが常に null を返すためであり、これがその名前の由来です。
Javaコード
次のようにコードをコピーします。
@テスト
public void phantomReferenceAlwaysNull() {
オブジェクト参照 = new Object();
PhantomReference<Object> phantomReference = new PhantomReference<Object>(referent, new ReferenceQueue<Object>());
/**
※ファントム参照のgetメソッドは常にnullを返します
*/
assertNll(phantomReference.get());
}
常に null を返す参照はどのような用途に使用されるのでしょうか? PhantomReference を構築するときは、2 番目のパラメーター ReferenceQueue に注意してください (実際、WeakReference と SoftReference にもこのパラメーターを含めることができます)。
PhantomReference の唯一の用途は、参照対象が ReferenceQueue にエンキューされるタイミングを追跡することです。
5. 関連性キュー
WeakReference が null を返し始めると、それが指すオブジェクトはリサイクルできるようになります。この時点で、オブジェクトがリサイクルされるときに、ReferenceQueue を Reference のコンストラクターに渡すことができます。オブジェクトは ReferenceQueue に自動的に挿入されます。WeakHashMap は ReferenceQueue を使用して、キーに強い参照がなくなったエントリをクリアします。
Javaコード
次のようにコードをコピーします。
@テスト
public void ReferenceQueue() は InterruptedException をスローします {
オブジェクト参照 = new Object();
ReferenceQueue<Object>referenceQueue = new ReferenceQueue<Object>();
WeakReference<Object>weakReference = new WeakReference<Object>(referent,referenceQueue);
assertFalse(weakReference.isEnqueued());
Reference<? extends Object> ポーリング =referenceQueue.poll();
アサートNull(ポーリング);
参照先 = null;
System.gc();
assertTrue(weakReference.isEnqueued());
参照<? オブジェクトを拡張> 削除 =referenceQueue.remove();
assertNotNull(削除されました);
}
6. PhantomReference と WeakReference の比較
PhantomReference には 2 つの利点があります。1 つ目は、オブジェクトがいつメモリから削除されるかを正確に知ることができることです (分散 GC、XWork、google-guice などでも PhantomReference がクリーンアップ作業を行った場合など)。
第二に、ファイナライズによって引き起こされるいくつかの根本的な問題を回避できます。前述したように、PhantomReference の唯一の機能は、参照対象が ReferenceQueue にエンキューされるタイミングを追跡することですが、WeakReference にも対応する機能があります。この 2 つの違いは何でしょうか。
これは Object の Finalize メソッドに関するものです。このメソッドは、gc が実行される前に呼び出されます。オブジェクトが Finalize メソッドをオーバーロードし、メソッド内でそれ自体への強い参照を作成すると、このラウンドの GC が実行できなくなります。このオブジェクトは GC を引き起こす可能性があり、最終的には JVM 内に大量のゴミが発生しますが、PhantomReference は Finalize メソッドの実行後にリサイクルされるため、この問題は回避できます。もちろん、これは非常に極端な例であり、通常は発生しません。
7. 比較
ソフトリファレンス、ウィークリファレンス、ファントムリファレンス | ||||
---|---|---|---|---|
タイプ | 目的 | 使用 | GC 時 | 実装クラス |
強力な参照 | 通常の参照。オブジェクトが参照されている限り存続します。 | 通常のリファレンス。 | 指されていないオブジェクトはすべて再利用できます。 | デフォルト |
ソフトリファレンス | 十分なメモリがある場合、オブジェクトを存続させます。 | クライアントがキーによって参照を再度要求し始めた場合に備えて、クライアントが参照 (メモリに依存するキャッシュ) を削除した後でもオブジェクトを存続させておくため。 | 最初の gc パスの後、JVM はさらに多くのスペースを再利用する必要があると判断します。 | java.lang.ref.SoftReference |
弱参照 | オブジェクトがクライアントによって使用されている (到達可能) 間のみ、オブジェクトを存続させます。 | 使用されなくなったオブジェクトを自動的に削除するコンテナー。 | gc がオブジェクトの到達可能性が低いと判断した後 | java.lang.ref.WeakReference java.util.WeakHashMap |
ファントムリファレンス | ファイナライズ後、スペースが再利用される前にクリーンアップできます (finalize() の使用を置き換えまたは拡張します)。 | 特殊クリーンアップ処理 | ファイナライズ後。 | java.lang.ref.PhantomReference |
8. まとめ
一般的なアプリケーションにはリファレンス プログラミングは含まれませんが、この知識を理解すると、GC の動作原理やパフォーマンス チューニングを理解するのに役立ちます。この記事が役立つことを願っています。