PhantomReference可以阻止内存回收吗?

问题描述 投票:4回答:1

我的问题总结了一切:

  • 可强制访问的Java PhantomReference是否可以阻止其引用对象的内存被垃圾收集器(GC)回收?

细节如下:

Callum posted this question也是如此,但没有直截了当地回答。那里的一个回应是指Ethan Nicholas的一篇文章,似乎用“否”回答了我的问题,但我不确定这是否正确。

基于我对Java API的阅读,我将不得不用“是”回答我的问题:

  • 只要没有调用PhantomReference.clear(),并且仍然强烈引用PhantomReference实例本身,将永远不会回收引用对象的内存,并且引用将保持在幻像可达状态。

为了支持这种理解,我将引用Java Docs

  • “与软引用和弱引用不同,垃圾收集器在它们入队时不会自动清除幻像引用。通过幻像引用可以访问的对象将保持不变,直到所有这些引用都被清除或者它们本身无法访问。”

例如,假设我做了一个幻像引用并将该实例保存在PhantomReference列表中。然后它的指示物从强烈可达到幻象可达。

如果您查看com.google.common.base.internal.Finalizer.java,您将看到以下代码:

  private void cleanUp(Reference reference) throws ShutDown {
      ...

      /*
       * This is for the benefit of phantom references. Weak and soft
       * references will have already been cleared by this point.
       */
      reference.clear();

      ...
  }

我希望有经验的人能够做出回应,而不是进行网络搜索并向我提供链接。谢谢!

java reference garbage-collection weak-references phantom-reference
1个回答
2
投票

你混合了两件事。链接的问题不是关于指示物,而是关于PhantomReference实例。像所有引用对象一样,PhantomReference实例可以像任何其他对象一样收集垃圾,只要它没有排队。这在package specification中指定:

已注册的参考对象与其队列之间的关系是片面的。也就是说,队列不会跟踪向其注册的引用。如果注册的引用本身无法访问,那么它将永远不会被入队。使用引用对象的程序负责确保只要程序对其引用对象感兴趣,对象就可以保持可达。

但你的问题是关于指称物。此外,引用的代码是关于处理已经入队甚至从队列中检索的引用。

在这个地方,您引用的文档适用。直到并包括Java 8,可以自动清除可达PhantomReferences的引用,因此引用保持幻像可达,直到引用被清除或变得无法访问。因此,引用的代码在明确清除引用以允许早期回收时是正确的,但差异仅影响清理方法执行的持续时间,因为之后,PhantomReference本身可能变得无法访问。


但这不是故事的结局。没有明确的理由说明参考物应该保持幻影可达而不是被收回。毕竟,清理方法无论如何都无法访问指示对象。

因此Java 9会删除该规则并自动清除幻像引用,就像任何其他引用一样。因此,从Java 9开始,手动清除已经排队的幻像引用是不必要的,但当然不会受到影响,因此旧软件仍然可以顺利运行。


关于你的例子:

...让我说我做了一个幻像引用并将该实例保存在PhantomReference列表中。然后它的指示物从强烈可达到幻象可达。

仅仅作为PhantomReference参考的指示物并不足以使幻象达到。它还要求没有强引用并且对象已经完成,尽管对于大多数对象实际上跳过了最终化,因为它们没有自定义的finalize()方法。当幻像引用另外有软引用时,它可能取决于配置和内存需求,引用对象是否会变为幻像可达。

© www.soinside.com 2019 - 2024. All rights reserved.