PhantomReference可以阻止内存回收吗?

时间:2015-05-28 07:47:17

标签: java reference garbage-collection weak-references phantom-reference

我的问题总结了一切:

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

详细信息如下:

Callum posted this question但也没有直截了当地回答。其中一个回复是Ethan Nicholas的一篇文章,似乎用一个" No"来回答我的问题。但我不确定这是否正确。

基于我对Java API的阅读,我必须回答我的问题"是":

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

为了支持这种理解,我将引用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();

      ...
  }

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

1 个答案:

答案 0 :(得分:2)

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

中指定
  

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

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

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

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

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

关于你的例子:

  

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

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