繁体   English   中英

GC是否保证已清除的引用按拓扑顺序排入ReferenceQueue?

[英]Does GC guarantee that cleared References are enqueued to ReferenceQueue in topological order?

假设有两个对象, AB ,并且有一个指针Ax --> B ,我们使用相关的ReferenceQueueAB创建WeakReference

假设AB无法访问。 A之前,直观B不能被视为无法到达。 在这种情况下,我们以某种方式得到了保证,相应的参考文献将在直觉(拓扑时,有没有周期)的顺序排队ReferenceQueue 即ref(B)之前的参考(A)。 我不知道 - 如果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是对使用过的ReferenceQueue的PhantomReference,因此如果这是GC,则没有Finalizable {Weak,Soft,Phantom}引用可以存活,因为它们引用队列。 所以他们必须在队列本身可以被GC之前进行GC' - 但是,我们仍然可以保证这些引用将按照它们获得“垃圾收集”的顺序排入ReferenceQueue (就像它们获得GC一样) '一个接一个)? 代码暗示存在某种保证,否则理论上未处理的引用可以保留在队列中。

谢谢

我很确定答案是否定的。

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

Java虚拟机对finalize方法调用没有强制排序。 可以以任何顺序或甚至同时调用终结器。 JVM规范2.17.7

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

没有订购保证。 在Finalizer.java的情况下,可以在处理所有引用之前关闭线程。 查看FinalizableReferenceQueue的文档:

  • 保持对此对象的强引用,直到所有关联

  • 所指的对象已经定稿。 如果此对象是先前收集的垃圾,
  • 支持线程不会调用{@code finalizeReferent()}
  • 其余的参考。

这是故意的行为。 例如,当清除对键和/或值的引用时,我们使用FRQ清除映射条目。 如果用户不再具有对地图的引用,并且反过来不再具有对FRQ的引用,则处理这些引用没有意义。

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM