java - 为什么 PhantomReference 应该优先于最终确定?

标签 java garbage-collection finalize phantom-reference

它们都可以用于清理,几乎没有保证,但是 PR 需要更多的线束编码。那么,有两个选择,为什么我必须更喜欢一个而不是另一个?

Javadoc 9 describes finalize问题很大,但这并不会自动使它的替代方案变得更好,对吧?

此外,javadoc 将 PhantomReference 描述为提供“当对象变得不可访问时释放资源的更灵活和有效的方法”,但没有指定原因。好吧,我想这些人知道一些 secret ,但我想知道 - 不能让这个选择更明显吗?

区别

这是我发现的finalize(FZ)和pantom reference(PR)之间的所有区别,如果我遗漏了什么,请纠正我。

  1. 可以用于清理操作吗?

    • 两者都是。
  2. 需要一个新线程来维护?

    • PR:是的,您必须定义一个队列观察线程以便尽快进行清理
    • FZ:没有
  3. 需要一个新类来定义?

    • PR:是的,您必须扩展 PhantomReference 才能进行有意义的操作
    • FZ:没有
  4. 清理处理器能否访问引用对象?

    • 公关:否
    • FZ:是的,这很方便
  5. 它在我的个人实践中是否可靠?

    • 两者都是。
  6. 会导致性能问题、死锁和挂起吗?

    • 两者都是。取决于您的代码,不是吗?
  7. 清理处理器中的错误会导致资源泄漏吗?

    • 两者都是。取决于您的代码,不是吗?
  8. 如果不再需要可以取消吗?

    • 公关:是
    • FZ:不,如果严格来说,立即返回有那么糟糕吗?
  9. 是否指定了多个实例之间的调用顺序?

    • 公关:无信息
    • FZ: 否 - “在不同对象的终结方法调用之间未指定顺序”(java.lang.Object)
  10. 保证调用?

    • PR:无信息 - 您只能“请求通知对象可达性的更改”(java.lang.ref)
    • FZ:否 - “finalize 方法只能在无限期延迟后才能在可终结对象上调用,如果有的话” (java.lang.Object)
  11. 关于时间的任何保证?

    • PR:否 - “在垃圾收集器确定引用对象的可达性已更改为与引用类型对应的值后的某个时间”(java.lang.ref)
    • FZ:否 - “Java 编程语言没有指定调用终结器的时间”(JLS),“只有在无限期延迟之后才能在可终结对象上调用终结方法,如果有的话”(java .lang.Object)
  12. this 能否在处理过程中复活?

    • 公关:不,这还不错
    • FZ:是的,官方支持

链接:

最佳答案

其中大部分已在 Should Java 9 Cleaner be preferred to finalization? 中得到解决已经。由于 Cleaner API 建立在 PhantomReference 之上,因此大部分内容也适用于直接使用 PhantomReference

简而言之,您应该将finalize() 用法替换为PhantomReferenceCleaner。对于非内存资源,您应该更喜欢在使用后立即显式关闭,使用 try-with-resources在可行的地方 build 。与垃圾收集器的交互可以作为检测编程错误的回退,但不应成为资源清理的首选方式。

在这方面,在资源正确关闭时选择退出清理的能力具有重要意义,因为这将成为常态。你低估了它的影响。曾经,您的类有一个非平凡的终结器,它的对象需要两个垃圾收集周期才能被回收,即使 finalize() 在检查条件后立即返回也是如此。这可能会导致在次要 gc 中被回收或被提升到老年代。

最极端的例子是由纯本地对象表示的短期使用资源,在应用逃逸分析后,其内存分配可能会被完全消除,而存在一个非平凡的 finalize() 方法总是意味着全局转义会阻止这种优化(除其他外,如锁消除)。

虽然 Cleaner API 会启动一个专用线程,但在使用 PhantomReference 时不需要这样做。您也可以在使用资源或即将分配新资源时轮询队列。这并不能保证资源的快速释放(gc 触发的清理无论如何都不能保证),但您可以确保分配不会在收集的对象不必要地持有资源时失败。

即使您使用专用线程进行清理,在您的控制下启动线程与由您控制之外的未指定 JVM 线程调用终结器之间存在根本区别,其中错误的 finalize() 方法另一个库可能会阻塞清理所需的线程。 JVM 可以同时调用多个终结器,而您可以决定使用多少线程进行基于 PhantomReference 的清理。

关于java - 为什么 PhantomReference 应该优先于最终确定?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57539290/

相关文章:

java - 为什么在Java 9中不推荐使用finalize()方法?

Java Hibernate Spring AnnotationException 未映射类

java - 为什么要重写 Java 中的克隆方法

java - 通过 Twitter4J 进行多线程 Twitter 访问

c# - 窗体关闭后如何显示?

python - numpy.ndarray 对象未被垃圾收集

java - java中的内存泄漏

java - 缩放 JComponent 以适合页面页面

java - JAVA中的垃圾收集(标记-清除和引用计数)

angular - rxjs takeUntil 不执行finalize