4

假设有两个对象AB,并且有一个指针A.x --> B,我们创建,比如说,WeakReferences 到两个AB,并带有一个关联的ReferenceQueue

假设两者都A变得B无法访问。直觉B上不能认为是不可到达A的。在这种情况下,我们是否能以某种方式保证各个引用将按直观(没有循环时的拓扑)顺序排列ReferenceQueue?即 ref(A) 在 ref(B) 之前。我不知道——如果 GC 将一堆对象标记为无法访问,然后以不特定的顺序将它们排入队列会怎样?

我正在审查番石榴的Finalizer.java,看到这个片段:

private void cleanUp(Reference<?> reference) throws ShutDown {
  ...
  if (reference == frqReference) {
    /*
     * The client no longer has a reference to the
     * FinalizableReferenceQueue. We can stop.
     */
    throw new ShutDown();
  }

frqReference是对 used 的 PhantomReference ReferenceQueue,所以如果这是 GC'ed,没有 Finalizable{Weak, Soft, Phantom}References 可以是活动的,因为它们引用了队列。所以它们必须在队列本身可以被 GC 之前被 GC ——但是,我们是否得到保证这些引用将按ReferenceQueue它们“收集垃圾”的顺序排入队列(就像他们得到 GC'一个接一个)?该代码暗示存在某种保证,否则理论上未处理的引用可能会保留在队列中。

谢谢

4

3 回答 3

4

我很确定答案是否定的。

JVM 规范说明了终结器方法:

Java 虚拟机没有对 finalize 方法调用进行排序。终结器可以按任何顺序调用,甚至可以同时调用。(JVM 规范 2.17.7

由此我推断,不能保证引用按拓扑顺序排队。

于 2010-03-23T03:40:07.687 回答
3

There is no ordering guarantee. In the case of Finalizer.java, the thread can be shut down before all references are processed. See the docs for FinalizableReferenceQueue:

  • Keep a strong reference to this object until all of the associated

  • referents have been finalized. If this object is garbage collected earlier,
  • the backing thread will not invoke {@code finalizeReferent()} on the
  • remaining references.

This is intentional behavior. For example, we use FRQ to clean up map entries when references to the keys and/or values are cleared. If the user no longer has a reference to the map, and in turn no longer has a reference to the FRQ, there's no point in processing those references.

于 2010-03-23T17:33:03.897 回答
1

我认为没有这样的保证。GC 本身并没有完整和即时的 RAM 视图(它不能,因为 GC 在 CPU 上运行,它一次只能查看几个字节)。在您的示例中,假设一个基本的“标记和扫描”GC,很可能 A 和 B 将在同一标记阶段被声明为不可访问,并且没有特定的顺序一起扫描。维护拓扑顺序可能会很昂贵。

至于Finalizer,似乎它只能通过FinalizableReferenceQueue实例使用,它会执行一些与类加载器相关的魔法。使用Finalizer自己的设施来检测FinalizableReferenceQueue它在功能上依赖的 何时变得无法访问;这是运行的线程Finalizer知道它应该退出的时间点。据我了解,如果应用程序让 GC 回收 FRQ,那么终结器线程将退出,并且在 FRQ 引用“之后”排队的任何引用都不会被处理。这取决于拓扑顺序或缺乏拓扑顺序,但我无法确定这是否是一个问题。我认为只要处理回收的引用对象很重要,应用程序就不应该放弃它的 FRQ。

于 2010-03-23T14:38:22.747 回答