私が知ってPhantomReference
いる唯一のことは、
- この
get()
メソッドを使用するnull
と、オブジェクトではなく常に返されます。それの用途は何ですか? - を使用
PhantomReference
することにより、オブジェクトがfinalize
メソッドから復活できないことを確認します。
しかし、このコンセプト/クラスの用途は何ですか?
これをプロジェクトで使用したことはありますか、またはこれを使用する必要がある例はありますか?
私が知ってPhantomReference
いる唯一のことは、
get()
メソッドを使用するnull
と、オブジェクトではなく常に返されます。それの用途は何ですか?PhantomReference
することにより、オブジェクトがfinalize
メソッドから復活できないことを確認します。しかし、このコンセプト/クラスの用途は何ですか?
これをプロジェクトで使用したことはありますか、またはこれを使用する必要がある例はありますか?
FakeReference
orまたはが呼び出されているはずNonReference
です。
回答:
単純化さPhantomReference
れた、非常に特殊な種類のメモリプロファイラで s を使用しましたオブジェクトの作成と破棄を監視するためを使用しました。破壊を追跡するために彼らに必要でした。しかし、このアプローチは時代遅れです。(J2SE 1.4をターゲットに2004年に記述されました。)プロのプロファイリングツールははるかに強力で信頼性が高く、JMXやエージェントなどの新しいJava 5機能とJVMTIも使用できます。
PhantomReference
s(常に参照キューと一緒に使用されます)は、finalize
いくつかの問題がある場合よりも優れているため、回避する必要があります。主にオブジェクトを再び到達可能にする。これは、ファイナライザガーディアンイディオム(->「効果的なJava」で詳細を読む)で回避できます。したがって、これらも新しいファイナライズです。
さらに、PhantomReference
s
オブジェクトがメモリからいつ削除されたかを正確に判断できます。それらは実際にそれを決定する唯一の方法です。これは一般的にはそれほど便利ではありませんが、大きな画像の操作など、特定の非常に特殊な状況で役立つことがあります。画像がガベージコレクションの対象であることが確実にわかっている場合は、次の画像を読み込もうとする前に、実際に待機することができます。 、したがって、恐ろしいOutOfMemoryErrorの可能性を低くします。(enicholasから引用)
そして、psdが最初に書いたように、Roedy Greenは参考文献の良い要約を持っています。
Java Glossary の一般的なダイスアップテーブルの説明。
もちろん、これはPhantomReferenceドキュメントと一致します:
ファントム参照オブジェクト。これは、コレクターが他の方法でリファレントを再利用できると判断した後にエンキューされます。ファントム参照は、Javaファイナライズメカニズムよりも柔軟な方法で、事前のクリーンアップアクションをスケジュールするために最もよく使用されます。
そして最後に重要なことですが、すべての悲惨な詳細(これは良い読み物です):Java参照オブジェクト(または私がどのようにして心配をやめてOutOfMemoryErrorを愛するようになったか)。
ハッピーコーディング。(しかし、質問に答えるために、私はWeakReferencesを使用したことがありません。)
ファントム参照の使用法の素晴らしい説明:
ファントム参照は、オブジェクトがメモリから削除されたことを知るための安全な方法です。たとえば、大きな画像を扱うアプリケーションを考えてみましょう。大きな画像が既にガベージコレクションの準備ができているメモリにあるときに、大きな画像をメモリにロードするとします。そのような場合、古いイメージが収集されるまで待ってから、新しいイメージをロードします。ここで、ファントム参照は柔軟で安全に選択できます。古い画像オブジェクトがファイナライズされると、古い画像の参照がReferenceQueueにエンキューされます。その参照を受け取った後、新しい画像をメモリに読み込むことができます。
これは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と同じ方法です。しかし、私の解決策はもう少し一般的です。
単体テストで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>");
}
}
より適切なWeakReference
場所で使用するのが一般的PhantomReference
です。これWeakReference
により、ガベージコレクターによってオブジェクトがクリア/エンキューされた後にオブジェクトを復活させることができるという特定の問題が回避されます。人々は愚かなバガーを演じていないので、通常、違いは問題ではありません。
メソッドが機能しPhantomReference
ているように見せかけることができないため、使用するのは少し煩わしい傾向がありますget
。たとえば、を書くことはできませんPhantom[Identity]HashMap
。
weakref.get
を返すことができnull
、その後、それはまだobjを返すことができますか?
finalize
はオブジェクトをそのように再作成しません。からWeakReference
戻っnull
てget
キューに入れられた後、オブジェクトを再び強力に到達可能にすることができます。/(user166390:参照のターゲットをキーとするマップのように、参照WeakHashMap
のアイデンティティマップではなく、問題ありません。)
get()メソッドを使用すると、オブジェクトではなく常にnullが返されます。[次に、それの用途は何ですか]
(ではなくget()
)を呼び出すのに役立つメソッドは、isEnqueued()
またはreferenceQueue.remove()
です。これらのメソッドを呼び出して、オブジェクトのガベージコレクションの最終ラウンドで実行する必要があるアクションを実行します。
最初にオブジェクトがそのfinalize()
メソッドを呼び出されたときなので、そこにも閉じるフックを置くことができます。ただし、他の人が述べたように、クリーンアップを実行するより確実な方法や、ガベージコレクションの前後に、またはより一般的にはオブジェクトのサポート終了後に実行する必要のあるアクションがあります。
私は別の実用見つかっPhantomReferences
中LeakDetectorの桟橋のクラスを。
JettyはLeakDetector
クラスを使用して、クライアントコードがリソースを取得するがそれを解放しないかどうかを検出し、LeakDetector
クラスはPhantomReferences
この目的でを使用します。