理解Phantom引用与弱引用相对于引用队列的区别

7
根据链接https://weblogs.java.net/blog/enicholas/archive/2006/05/understanding_w.html,只有当对象从内存中被物理删除时,PhantomReferences才会排队,而在最终确定或垃圾回收实际发生之前,WeakReferences就已经排队了。

差异在于排队的时间点。 当指向的对象变成弱可达时,弱引用立即排队, 这是在最终确定或垃圾回收实际发生之前; 理论上,该对象甚至可以通过非正规的finalize()方法"复活", 但弱引用将保持死亡状态。 而只有当对象从内存中被物理删除时,幽灵引用才会排队, 并且get()方法始终返回null,特别是为了防止您能够"复活"一个几乎死亡的对象。

然而,根据http://www.ibm.com/developerworks/library/j-refs/PhantomReference在堆对象被释放之前添加到其ReferenceQueue中,而WeakReferences在最终确定或垃圾回收之后添加到其ReferenceQueue中。

与软引用和弱引用不同,幽灵引用在释放堆对象之前将被添加到其ReferenceQueue中。 (请记住,所有PhantomReference对象都必须与关联的ReferenceQueue一起创建。) 这允许在回收堆对象之前采取行动。

当堆对象的finalize()方法运行并且其内存被释放时, 如果存在,则将WeakReference对象添加到其ReferenceQueue中。

我很困惑。哪一个是正确的?
基本上我想知道弱引用和幽灵引用与引用队列相关的区别。
1个回答

9

关于ReferenceQueue:

如果WeakReference和PhantomReference在创建时注册了非空的引用队列,当它们的引用对象不再具有强引用时,它们都将被加入到该队列中。

在传递给引用队列之前,WeakReference会清除(置为null)引用字段以使引用对象完全不可达。当WeakReference被清除时,应用程序将无法获取引用对象。这意味着,当稍后WeakReference被加入队列时,get()方法返回null。创建WeakReference时可能没有注册引用队列。应用程序可以通过get()方法检测其引用对象是否不可达。有时,当应用程序不想显式管理WeakReferences时,引用队列很方便。

在传递给引用队列之前,PhantomReference不会清除引用字段。当它被加入队列时,引用对象仍然被PhantomReference引用。引用对象只有在应用程序显式地从引用队列中取出后才会被清除。如果应用程序没有清除它,引用对象将一直保留,直到它和其PhantomReference一起被回收。无论何种情况下,即使未被清除,PhantomReference上的get()方法始终返回null。因此,应用程序无法通过get()方法检测其引用对象是否不可达。应用程序只能通过检查PhantomReference是否在队列中来检测其引用对象是否不可达。因此,必须使用已注册引用队列的PhantomReference;否则它是无用的。

关于finalization:

当WeakReference被清除时,引用对象变得不可达。如果引用对象具有非默认终结器,则会进行终结处理,从而使其复活。如果引用对象没有非默认终结器,则将被GC回收。换句话说,WeakReferences在终结之前进行处理。

如果PhantomReference的引用对象仅通过PhantomReference可达,则尚未成为幽灵引用。只有在终结之后仍然如此(仅通过PhantomReference可达),它才成为幽灵引用。换句话说,PhantomReferences在终结之后进行处理。只有那些没有被终结复活的引用对象才是幽灵引用,因此它们肯定会死亡。但是,由于PhantomReference稍后将被加入队列,这些引用对象尚未死亡。只有当应用程序稍后清除PhantomReferences或PhantomReferences本身变得不可达时(然后PhantomReference和其引用对象一起被回收),它们才会变得可回收。


我假设你写的每句话都是正确的,但我仍然完全不明白为什么我会需要 PhantomReference。(我经常使用 WeakReference,并且清楚它的作用。) - Stefan Reich
1
@StefanReich PhantomReference具有非常特殊的属性,即应用程序确切知道引用已经失效并且一定会被GC回收,也就是说,在入队之前已经完成了最终处理,因此永远不会被复活。这个属性在某些用例中非常重要。例如,您想在确保旧对象2可以被回收后才创建新对象1。 - Xiao-Feng Li
好的,我明白了。如果这是关于不会物理上耗尽内存,您需要PhantomReference保证对象已被释放。谢谢。 - Stefan Reich

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接