PhantomReferenceをプロジェクトで使用したことがありますか?


89

私が知ってPhantomReferenceいる唯一のことは、

  • このget()メソッドを使用するnullと、オブジェクトではなく常に返されます。それの用途は何ですか?
  • を使用PhantomReferenceすることにより、オブジェクトがfinalizeメソッドから復活できないことを確認します。

しかし、このコンセプト/クラスの用途は何ですか?

これをプロジェクトで使用したことはありますか、またはこれを使用する必要がある例はありますか?



PhantomReferenceの参照されたobjを取得できないため、完全な誤称:FakeReferenceorまたはが呼び出されているはずNonReferenceです。
パセリエ2017

これがコード付きの別のスレッドです:stackoverflow.com/q/43311825/632951
Pacerier

回答:


47

単純化PhantomReferenceれた、非常に特殊な種類のメモリプロファイラで s を使用しましたオブジェクトの作成と破棄を監視するためを使用しました。破壊を追跡するために彼らに必要でした。しかし、このアプローチは時代遅れです。(J2SE 1.4をターゲットに2004年に記述されました。)プロのプロファイリングツールははるかに強力で信頼性が高く、JMXやエージェントなどの新しいJava 5機能とJVMTIも使用できます。

PhantomReferences(常に参照キューと一緒に使用されます)は、finalizeいくつかの問題がある場合よりも優れているため、回避する必要があります。主にオブジェクトを再び到達可能にする。これは、ファイナライザガーディアンイディオム(->「効果的なJava」で詳細を読む)で回避できます。したがって、これらも新しいファイナライズです。

さらに、PhantomReferences

オブジェクトがメモリからいつ削除されたかを正確に判断できます。それらは実際にそれを決定する唯一の方法です。これは一般的にはそれほど便利ではありませんが、大きな画像の操作など、特定の非常に特殊な状況で役立つことがあります。画像がガベージコレクションの対象であることが確実にわかっている場合は、次の画像を読み込もうとする前に、実際に待機することができます。 、したがって、恐ろしいOutOfMemoryErrorの可能性を低くします。(enicholasから引用)

そして、psdが最初に書いたように、Roedy Greenは参考文献の良い要約を持っています


21

Java Glossary の一般的なダイスアップテーブルの説明

もちろん、これはPhantomReferenceドキュメントと一致します

ファントム参照オブジェクト。これは、コレクターが他の方法でリファレントを再利用できると判断した後にエンキューされます。ファントム参照は、Javaファイナライズメカニズムよりも柔軟な方法で、事前のクリーンアップアクションをスケジュールするために最もよく使用されます。

そして最後に重要なことですが、すべての悲惨な詳細(これは良い読み物です):Java参照オブジェクト(または私がどのようにして心配をやめてOutOfMemoryErrorを愛するようになったか)

ハッピーコーディング。(しかし、質問に答えるために、私はWeakReferencesを使用したことがありません。)


ところで、その記事についての質問です。PhantomReferenceのセクションでは、これら2つのテーブルを通じて接続オブジェクトへの強い参照を保持しています。これは、接続が到達不能になることは決してないことを意味します(プールインスタンス自体が到達不能になることはないと想定しています)。したがって、対応するPhantomReferencesは決してキューに入れられませんよね?それとも何か不足していますか?
shrini1000 2012年

1
うわー、kdgregoryからのその記事は+10に値します
パセリエ

14

ファントム参照の使用法の素晴らしい説明

ファントム参照は、オブジェクトがメモリから削除されたことを知るための安全な方法です。たとえば、大きな画像を扱うアプリケーションを考えてみましょう。大きな画像が既にガベージコレクションの準備ができているメモリにあるときに、大きな画像をメモリにロードするとします。そのような場合、古いイメージが収集されるまで待ってから、新しいイメージをロードします。ここで、ファントム参照は柔軟で安全に選択できます。古い画像オブジェクトがファイナライズされると、古い画像の参照がReferenceQueueにエンキューされます。その参照を受け取った後、新しい画像をメモリに読み込むことができます。


12

私はの実用的で有用なユースケース見つかっPhantomReferenceあるorg.apache.commons.io.FileCleaningTrackerコモンズ-IOプロジェクトでは。FileCleaningTrackerマーカーオブジェクトがガベージコレクションされると、物理ファイルが削除されます。
注意すべきことは、Trackerクラスを拡張するPhantomReferenceクラスです。


5

これはJAVA 9では廃止する必要があります!代わりに
使用してくださいjava.util.Cleaner!(またはsun.misc.Cleaner古いJREで)

元の投稿:


PhantomReferencesを使用すると、ファイナライザメソッドとほぼ同じ量の落とし穴があることがわかりました(ただし、正しく設定すると問題は少なくなります)。Java 8用の小さなソリューション(PhantomReferencesを使用するための非常に小さなフレームワーク)を作成しました。これにより、オブジェクトが削除された後に実行されるコールバックとしてラムダ式を使用できます。クローズする必要がある内部リソースのコールバックを登録できます。これで私はそれがはるかに実用的になるので私のために働く解決策を見つけました。

https://github.com/claudemartin/java-cleanup

以下は、コールバックがどのように登録されるかを示す小さな例です。

  class Foo implements Cleanup {
    //...  
    public Foo() { 
    //...    
      this.registerCleanup((value) -> {
        try {
          // 'value' is 'this.resource'
          value.close();
        } catch (Exception e) {
          logger.warning("closing resource failed", e);
        }
      }, this.resource);
    }

そして、自動クローズのさらに簡単な方法があり、上記とほぼ同じです:

this.registerAutoClose(this.resource);

あなたの質問に答えるには:

[次に、それの用途は何ですか]

存在しないものを片付けることはできません。しかし、まだ存在していて、削除できるようにクリーンアップする必要があるリソースがあった可能性があります。

しかし、このコンセプト/クラスの用途は何ですか?

デバッグ/ロギング以外の効果を伴うことは必ずしも必要ではありません。または多分統計のために。GCからの通知サービスに似ています。また、これを使用して、オブジェクトが削除されると無関係になる集約データを削除することもできます(ただし、おそらくより良い解決策があります)。例では、データベース接続が閉じられることを頻繁に言及していますが、トランザクションを処理できなかったため、これがどのように良いアイデアであるかはわかりません。アプリケーションフレームワークは、そのためのはるかに優れたソリューションを提供します。

これをプロジェクトで使用したことはありますか、またはこれを使用する必要がある例はありますか?または、このコンセプトはインタビューの観点からのみ作成されたものですか;)

私は主にロギングのためだけにそれを使用します。削除された要素を追跡して、GCがどのように機能し、調整できるかを確認できます。この方法で重要なコードを実行することはありません。何かを閉じる必要がある場合は、try-with-resource-statementで行う必要があります。また、単体テストでそれを使用して、メモリリークがないことを確認します。jontejjと同じ方法です。しかし、私の解決策はもう少し一般的です。


はい、私のソリューション「java-cleanup」と同じように。どちらも抽象化であるため、直接処理する必要はありません。
クロードマーティン

3

単体テストでPhantomReferenceを使用して、テスト中のコードが一部のオブジェクトへの不要な参照を保持していないことを確認しました。(元のコード

import static com.google.common.base.Preconditions.checkNotNull;
import static org.fest.assertions.Assertions.assertThat;

import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;

import com.google.common.testing.GcFinalization;

/**
* Helps to test for memory leaks
*/
public final class MemoryTester
{
private MemoryTester()
{
}

/**
* A simple {@link PhantomReference} that can be used to assert that all references to it is
* gone.
*/
public static final class FinalizationAwareObject extends PhantomReference<Object>
{
private final WeakReference<Object> weakReference;

private FinalizationAwareObject(Object referent, ReferenceQueue<Object> referenceQueue)
{
super(checkNotNull(referent), referenceQueue);
weakReference = new WeakReference<Object>(referent, referenceQueue);
}

/**
* Runs a full {@link System#gc() GC} and asserts that the reference has been released
* afterwards
*/
public void assertThatNoMoreReferencesToReferentIsKept()
{
String leakedObjectDescription = String.valueOf(weakReference.get());
GcFinalization.awaitFullGc();
assertThat(isEnqueued()).as("Object: " + leakedObjectDescription + " was leaked").isTrue();
}
}

/**
* Creates a {@link FinalizationAwareObject} that will know if {@code referenceToKeepTrackOff}
* has been garbage collected. Call
* {@link FinalizationAwareObject#assertThatNoMoreReferencesToReferentIsKept()} when you expect
* all references to {@code referenceToKeepTrackOff} be gone.
*/
public static FinalizationAwareObject createFinalizationAwareObject(Object referenceToKeepTrackOff)
{
return new FinalizationAwareObject(referenceToKeepTrackOff, new ReferenceQueue<Object>());
}
}

そしてテスト

@Test
public void testThatHoldingOnToAnObjectIsTreatedAsALeak() throws Exception
{
    Object holdMeTight = new String("Hold-me-tight");
    FinalizationAwareObject finalizationAwareObject = MemoryTester.createFinalizationAwareObject(holdMeTight);
    try
    {
    finalizationAwareObject.assertThatNoMoreReferencesToReferentIsKept();
    fail("holdMeTight was held but memory leak tester did not discover it");
    }
    catch(AssertionError expected)
    {
    assertThat(expected).hasMessage("[Object: Hold-me-tight was leaked] expected:<[tru]e> but was:<[fals]e>");
    }
}

2

より適切なWeakReference場所で使用するのが一般的PhantomReferenceです。これWeakReferenceにより、ガベージコレクターによってオブジェクトがクリア/エンキューされた後にオブジェクトを復活させることができるという特定の問題が回避されます。人々は愚かなバガーを演じていないので、通常、違いは問題ではありません。

メソッドが機能しPhantomReferenceているように見せかけることができないため、使用するのは少し煩わしい傾向がありますget。たとえば、を書くことはできませんPhantom[Identity]HashMap


IdentityHashMap <PhantomReference>は、実際にはIdentityHashMapに適した場所の1つです。強い参照はPhantomReferenceに保持されますが、参照先には保持されないことに注意してください。

弱い参照の場合、finalizeがobjを再作成する可能性があるということですか? weakref.getを返すことができnull、その後、それはまだobjを返すことができますか?
パセリエ2017

@Pacerier finalizeはオブジェクトをそのように再作成しません。からWeakReference戻っnullgetキューに入れられた後、オブジェクトを再び強力に到達可能にすることができます。/(user166390:参照のターゲットをキーとするマップのように、参照WeakHashMapのアイデンティティマップではなく、問題ありません。)
Tom Hawtin-タックライン'18

1

get()メソッドを使用すると、オブジェクトではなく常にnullが返されます。[次に、それの用途は何ですか]

(ではなくget())を呼び出すのに役立つメソッドは、isEnqueued()またはreferenceQueue.remove()です。これらのメソッドを呼び出して、オブジェクトのガベージコレクションの最終ラウンドで実行する必要があるアクションを実行します。

最初にオブジェクトがそのfinalize()メソッドを呼び出されたときなので、そこにも閉じるフックを置くことができます。ただし、他の人が述べたように、クリーンアップを実行するより確実な方法や、ガベージコレクションの前後に、またはより一般的にはオブジェクトのサポート終了後に実行する必要のあるアクションがあります。


1

私は別の実用見つかっPhantomReferencesLeakDetectorの桟橋のクラスを。

JettyはLeakDetectorクラスを使用して、クライアントコードがリソースを取得するがそれを解放しないかどうかを検出し、LeakDetectorクラスはPhantomReferencesこの目的でを使用します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.