1. 概要

この記事では、Java言語での弱参照の概念について説明します。

これらが何であるか、それらが何に使用されるか、そしてそれらを適切に操作する方法を説明します。

2. 弱参照

弱く参照されているオブジェクトは、弱く到達可能になるとガベージコレクターによってクリアされます。

到達可能性が弱いということは、オブジェクトがそれを指す強い参照も柔らかい参照もないことを意味します。 弱参照をトラバースすることによってのみ、オブジェクトに到達できます。

まず、ガベージコレクターが弱参照をクリアするため、指示対象にアクセスできなくなります。 次に、参照は参照キュー(関連付けられている場合)に配置され、そこから取得できます。

同時に、以前は到達力が弱かったオブジェクトが完成する予定です。

2.1. 弱い参照と柔らかい参照

弱い参照と弱い参照の違いが不明確な場合があります。 ソフト参照は基本的に大きなLRUキャッシュです。 つまり、指示対象が近い将来再利用される可能性が高い場合は、ソフト参照を使用します

ソフト参照はキャッシュとして機能するため、指示対象自体が到達可能でなくても、到達可能であり続ける可能性があります。 実際のところ、ソフト参照は次の場合にのみ収集の対象となります。

  • 指示対象に強く到達できない
  • ソフトリファレンスは最近アクセスされていません

そのため、指示対象が到達不能になった後、数分または数時間もソフト参照が利用できる場合があります。 一方、弱参照は、その指示対象がまだ存在している間のみ使用できます。

3. ユースケース

Javaのドキュメントに記載されているように、弱参照は、正規化マッピングを実装するために最もよく使用されます。 マッピングが特定の値のインスタンスを1つだけ保持している場合、そのマッピングは正規化されたと呼ばれます。 新しいオブジェクトを作成するのではなく、マッピングで既存のオブジェクトを検索して使用します。

もちろん、これらの参照の最もよく知られている使用法はWeakHashMapクラスです。 これは、 Map インターフェースの実装であり、すべてのキーが指定されたキーへの弱参照として格納されます。 ガベージコレクターがキーを削除すると、このキーに関連付けられているエンティティも削除されます。

詳細については、WeakHashMapガイドをご覧ください。

それらを使用できるもう1つの領域は、LapsedListener問題です。

パブリッシャー(またはサブジェクト)は、発生したイベントについて通知するために、すべてのサブスクライバー(またはリスナー)への強力な参照を保持します。 この問題は、リスナーがパブリッシャーから正常にサブスクライブを解除できない場合に発生します。

したがって、リスナーへの強力な参照は引き続きパブリッシャーが利用できるため、リスナーをガベージコレクションすることはできません。 その結果、メモリリークが発生する可能性があります。

この問題の解決策は、オブザーバーへの弱参照を保持しているサブジェクトであり、サブスクライブを解除しなくても前者をガベージコレクションできるようにすることができます(これは完全な解決策ではなく、そうでない他の問題が発生することに注意してください)。ここで説明します)。

4. 弱参照の操作

弱参照は、java.lang.ref.WeakReferenceクラスで表されます。 指示対象をパラメーターとして渡すことで初期化できます。 オプションで、java.lang.ref.ReferenceQueueを提供できます。

Object referent = new Object();
ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();

WeakReference weakReference1 = new WeakReference<>(referent);
WeakReference weakReference2 = new WeakReference<>(referent, referenceQueue);

参照の指示対象は、 get メソッドでフェッチし、clearメソッドを使用して手動で削除できます。

Object referent2 = weakReference1.get();
weakReference1.clear();

この種の参照を安全に操作するためのパターンは、ソフト参照の場合と同じです。

Object referent3 = weakReference2.get();
if (referent3 != null) {
    // GC hasn't removed the instance yet
} else {
    // GC has cleared the instance
}

5. 結論

このクイックチュートリアルでは、Javaの弱参照の低レベルの概念を確認し、これらを使用するための最も一般的なシナリオに焦点を当てました。