Javaにおけるファントム参照

Javaでのファントム参照

1. 概要

この記事では、Java言語でのファントムリファレンスの概念について説明します。

2. ファントムリファレンス

ファントム参照には、softおよびweak参照との2つの大きな違いがあります。

We can’t get a referent of a phantom reference.リファレントにAPIを介して直接アクセスすることはできません。そのため、このタイプの参照を処理するには参照キューが必要です。

ガベージコレクターは、ファントム参照を参照キューafter the finalize method of its referent is executedに追加します。 インスタンスがまだメモリにあることを意味します。

3. ユースケース

それらが使用される2つの一般的なユースケースがあります。

最初の手法はto determine when an object was removed from the memoryで、これはメモリに敏感なタスクをスケジュールするのに役立ちます。 たとえば、大きなオブジェクトが削除されるのを待ってから、別のオブジェクトをロードできます。

2番目の方法はto avoid using the finalize method and improve thefinalization processです。

3.1. 例

次に、この種の参照がどのように機能するかを実際に理解するために、2番目のユースケースを実装しましょう。

まず、リソースをクリアするためのメソッドを定義するために、PhantomReferenceクラスのサブクラスが必要です。

public class LargeObjectFinalizer extends PhantomReference {

    public LargeObjectFinalizer(
      Object referent, ReferenceQueue q) {
        super(referent, q);
    }

    public void finalizeResources() {
        // free resources
        System.out.println("clearing ...");
    }
}


次に、強化されたきめ細かいファイナライズを作成します。

ReferenceQueue referenceQueue = new ReferenceQueue<>();
List references = new ArrayList<>();
List largeObjects = new ArrayList<>();

for (int i = 0; i < 10; ++i) {
    Object largeObject = new Object();
    largeObjects.add(largeObject);
    references.add(new LargeObjectFinalizer(largeObject, referenceQueue));
}

largeObjects = null;
System.gc();

Reference referenceFromQueue;
for (PhantomReference reference : references) {
    System.out.println(reference.isEnqueued());
}

while ((referenceFromQueue = referenceQueue.poll()) != null) {
    ((LargeObjectFinalizer)referenceFromQueue).finalizeResources();
    referenceFromQueue.clear();
}


まず、必要なすべてのオブジェクトを初期化します。referenceQueue –キューに入れられた参照を追跡するため、references –後でクリーニング作業を実行するため、largeObjects –大きなデータ構造を模倣するため。

次に、ObjectクラスとLargeObjectFinalizerクラスを使用してこれらのオブジェクトを作成します。

ガベージコレクターを呼び出す前に、largeObjectsリストを逆参照することにより、大量のデータを手動で解放します。 Runtime.getRuntime().gc()ステートメントのショートカットを使用してガベージコレクターを呼び出したことに注意してください。

System.gc()がガベージコレクションをすぐにトリガーしないことを知っておくことが重要です。これは、JVMがプロセスをトリガーするための単なるヒントです。

forループは、すべての参照がキューに入れられていることを確認する方法を示しています。各参照のtrueが出力されます。

最後に、whileループを使用して、キューに入れられた参照をポーリングし、それぞれのクリーニング作業を実行しました。

4. 結論

このクイックチュートリアルでは、Javaのファントムリファレンスを紹介しました。

これらが何であるか、そしてそれらがいくつかの単純で要点のある例でどのように役立つかを学びました。