您是否在任何项目中使用过PhantomReference?


89

我唯一了解的PhantomReference

  • 如果使用其get()方法,它将始终返回null而不是对象。它有什么用?
  • 通过使用PhantomReference,可以确保不能从finalize方法中复现该对象。

但是这个概念/类的用途是什么?

您是否曾在您的任何项目中使用过此功能,或者您有任何应使用此功能的示例?



由于您无法获得PhantomReference的引用obj,因此它是一个完整的错误称呼:它应该被称为FakeReferenceNonReference
Pacerier's

这是带有代码的anothre线程:stackoverflow.com/q/43311825/632951
Pacerier

Answers:


47

PhantomReference简单,非常专业的内存分析器中使用s 来监视对象的创建和销毁。我需要他们追踪破坏。但是这种方法已经过时了。(它于2004年针对J2SE 1.4编写。)专业的分析工具功能更强大,更可靠,并且JMX或代理和JVMTI等新的Java 5功能也可以用于此目的。

PhantomReferences(始终与Reference队列一起使用)优于s,finalize但存在一些问题,因此应避免使用。主要是使对象再次可达。这可以通过终结器保护语来避免(->在'Effective Java'中了解更多信息)。所以它们也是新的敲定

此外,PhantomReferences

使您可以准确确定何时从内存中删除对象。实际上,它们是确定这一点的唯一方法。通常这没有什么用,但是在某些非常特殊的情况下(例如处理大图像)可能会派上用场:如果您确定应该对图像进行垃圾回收,则可以等到它实际加载后再尝试加载下一个图像,因此避免发生可怕的OutOfMemoryError的可能性。(引自尼古拉斯。)

就像psd首先写的那样,罗迪·格林(Roedy Green)有很好的参考文献摘要


21

一个普通切块表解释,从Java词汇。

当然,哪一个与PhantomReference文档一致:

幻影参考对象,在收集器确定可以以其他方式收回其参考对象之后将其排队。与Java终结机制相比,虚拟引用最常用于以更灵活的方式调度事前清理操作。

最后但并非最不重要的一点是所有令人毛骨悚然的细节(这是一本不错的书):Java参考对象(或我如何学会停止担心和喜欢OutOfMemoryError)

快乐的编码。(但是要回答这个问题,我只使用过WeakReferences。)


顺便说一句,关于那篇文章的问题。在有关PhantomReference的部分中,他通过这两个表对连接对象进行了严格引用。这意味着连接将永远不会变得不可达(假设池实例本身永远不会变得不可达)。因此,相应的PhantomReferences将永远不会入队,对吗?还是我错过了什么?
shrini1000

1
哇,那本来自kdgregory的文章应该得到+10
Pacerier,

14

幻影参考用法的绝佳解释

虚拟引用是一种安全的方法,可以知道对象已从内存中删除。例如,考虑一个处理大图像的应用程序。假设当大图像已经在内存中准备好进行垃圾回收时,我们希望将大图像加载到内存中。在这种情况下,我们要等到旧图像被收集后再加载新图像。在这里,幻像引用是灵活而安全的选择。旧图像对象完成后,旧图像的引用将排队到ReferenceQueue中。收到该引用后,我们可以将新图像加载到内存中。


12

我发现了一个实用和有用的用例PhantomReferenceorg.apache.commons.io.FileCleaningTracker在公共-io的项目。FileCleaningTracker当其标记对象被垃圾回收时,它将删除物理文件。
需要注意的是Tracker扩展PhantomReference类的类。


5

JAVA 9应该过时了!
使用java.util.Cleaner,而不是!(要么sun.misc.Cleaner在较旧的JRE上)

原始帖子:


我发现PhantomReferences的使用与终结器方法具有几乎相同的陷阱(但是一旦正确使用,问题就会更少)。我为Java 8写了一个小的解决方案(使用PhantomReferences的很小的框架)。它允许使用lambda表达式作为在对象删除后要运行的回调。您可以为应该关闭的内部资源注册回调。有了这个,我找到了一个对我有用的解决方案,因为它使它更加实用。

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

通常WeakReferencePhantomReference更合适的地方使用。这样可以避免某些问题。WeakReference了在垃圾回收器清除/排队。通常,差异并不重要,因为人们并不是在玩傻瓜。

使用PhantomReference往往更具侵入性,因为您无法假装该get方法有效。例如,您不能编写Phantom[Identity]HashMap


IdentityHashMap <PhantomReference>实际上是IdentityHashMap的适当位置之一。请注意,强引用保持对PhantomReference 的引用但不引用

您实际上是说对于弱引用,finalize可能会重新创建obj? weakref.get可以返回null,然后再返回,它仍然可以返回obj?
Pacerier

@Pacerier finalize不会像这样重新创建对象。它可以在以后使物体强可再次WeakReference返回nullget和入队。/(user166390:就像在引用目标的键控映射中WeakHashMap一样,不是引用的身份映射也可以)。
Tom Hawtin-大头贴

1

如果使用其get()方法,它将始终返回null,而不返回对象。[那么它的用途是什么]

调用(而不是get())的有用方法是isEnqueued()referenceQueue.remove()。您将调用这些方法来执行需要在对象的最后一轮垃圾回收上执行的某些操作。

第一次是该对象finalize()调用其方法时,因此也可以在其中放置闭合钩子。但是,正如其他人指出的那样,可能存在更肯定的执行清理的方法,或者需要在垃圾回收之前或之后进行的任何操作,或者更一般地,在对象的寿命终止时进行任何操作。


1

PhantomReferences在Jetty的LeakDetector类中发现了另一个实际用途。

Jetty使用LeakDetector类来检测客户端代码是否获取资​​源但从未释放资源,并且LeakDetector该类PhantomReferences为此目的使用。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.