PhantomReference 能否阻止其引用对象进行内存回收?

Can a PhantomReference stop its referent from memory reclamation?

我的问题总结如下:

详情如下:

Callum posted this question as well but it is not answered straightforwardly. One response there refers to an article by Ethan Nicholas 这似乎用 "No" 回答了我的问题,但我不确定这是正确的。

根据我对 Java API 的阅读,我必须用 "Yes":

来回答我的问题

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

      ...
  }

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

你把两件事搞混了。链接的问题不是关于所指对象,而是关于 PhantomReference 实例。 PhantomReference 实例与所有引用对象一样,可以像任何其他对象一样被垃圾回收,只要它还没有入队。这在 package specification:

中指定

The relationship between a registered reference object and its queue is one-sided. That is, a queue does not keep track of the references that are registered with it. If a registered reference becomes unreachable itself, then it will never be enqueued. It is the responsibility of the program using reference objects to ensure that the objects remain reachable for as long as the program is interested in their referents.

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

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


但这还没有结束。没有明确的理由说明为什么 referents 应该保持 phantom reachable 而不是被回收。毕竟,cleanup 方法无论如何也访问不到 referent。

所以 Java 9 删除该规则并像任何其他引用一样自动清除幻影引用。所以从Java9开始,手动清除已经入队的phantom references是不必要的,当然,也没有坏处,所以旧软件仍然可以正常工作。


关于你的例子:

…let's say I make a phantom reference and keep that instance in a List of PhantomReference. Then its referent falls from strongly reachable to phantom reachable.

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