为什么你会实施finalize()?

我已经阅读了很多关于finalize()的新手Java问题,并且发现让人困惑的是没有人真正明白finalize()是清理资源的不可靠方法。 我看到有人评论说他们用它来清理Connections,这真的很可怕,因为唯一能够保证Connection关闭的唯一方法就是最终实现try(catch)。

我没有受过CS的教育,但是我已经在Java中专业编程了近十年,我从未见过任何人在生产系统中实现过finalize()。 这并不意味着它没有它的用​​途,或者我与之合作过的人一直在做对。

所以我的问题是,在实现finalize()方面有哪些用例可以通过语言中的另一个进程或语法无法更可靠地处理?

请提供具体的场景或经验,仅仅重复一个Java教科书,或者敲定用途是不够的,而不是这个问题的意图。


您可以将它用作持有外部资源(套接字,文件等)的对象的逆止器。 实现close()方法并记录它需要调用的方法。

如果您发现它尚未完成,请执行finalize()以执行close()处理。 也许有些东西倾向于stderr指出你是在清理了一个错误的调用者之后。

它在特殊/越野车情况下提供额外的安全性。 不是每个调用者都会每次都做正确的try {} finally {} 。 不幸的是,在大多数环境下都是如此。

我同意这很少需要。 正如评论者指出的那样,它带有GC开销。 只有在长时间运行的应用程序中需要“腰带和吊带”安全时才可使用。

从Java 9开始, Object.finalize()已被弃用! 他们将我们指向java.lang.ref.Cleanerjava.lang.ref.PhantomReference作为替代。


finalize()是JVM的一个暗示,它可能是非常好的在未指定的时间执行你的代码。 当你想让代码神秘地失败时,这很好。

在终结器中做任何重要的事情(基本上除了日志记录以外的任何事情)在三种情况下也是很好

  • 你想赌博其他最终对象仍然处于你的程序其余部分认为有效的状态。
  • 你想添加大量的检查代码给所有你的类的所有方法,以确保它们在最终确定后正确运行。
  • 你希望意外复活最终对象,并花费大量时间来弄清楚它们为什么不起作用,以及/或者为什么它们在最终发布时还没有完成。
  • 如果你认为你需要finalize(),有时候你真正想要的是一个幻影引用(在给出的例子中它可以持有对它的referand使用的连接的硬引用,并且在幻像引用排队后关闭它)。 这也具有它可能神秘地从未运行的特性,但是至少它不能调用方法或重新定位最终对象。 所以,对于那些你并不一定需要干净地关闭这种连接的情况而言,这恰好是正确的,但是你很喜欢,而且你的班级的客户不能或不会自己关闭(这实际上足够公平 - 如果你设计的接口在收集之前需要采取特定的操作,那么根本就有垃圾收集器的意义是什么?这只会让我们回到malloc / free的日子。)

    其他时候,你需要你认为自己管理的资源更加健壮。 例如,为什么你需要关闭该连接? 它最终必须基于系统提供的某种I / O(套接字,文件,无论什么),那么为什么当最低级别的资源被占用时,您不能依靠系统为您关闭它? 如果另一端的服务器绝对要求你清楚地关闭连接而不是丢弃插座,那么当有人绊倒运行代码的机器的电源线时,或者中间网络会熄灭,会发生什么?

    免责声明:我以前在JVM实现方面工作过。 我讨厌终结者。


    一个简单的规则:不要使用终结器。 事实上,一个对象有一个终结器(不管它执行什么代码)足以导致垃圾收集的相当大的开销。

    从Brian Goetz的一篇文章中:

    带有终结器的对象(那些具有非平凡的finalize()方法的对象)与没有终结器的对象相比具有相当大的开销,应该谨慎使用。 Finalizeable对象分配速度较慢,收集速度较慢。 在分配时,JVM必须向垃圾收集器注册任何可终结对象,并且(至少在HotSpot JVM实现中)可终结对象必须遵循比大多数其他对象更慢的分配路径。 同样,可最终确定的对象收集速度也较慢。 在可回收可最终对象之前,它至少需要两次垃圾回收循环(最好的情况),垃圾回收器必须做额外的工作来调用终结器。 结果是分配和收集对象花费的时间更多,并且垃圾收集器的压力更大,因为无法访问的可终结对象所使用的内存保留时间更长。 将这一点与终结者不能保证在任何可预测的时间范围内运行的事实相结合,并且您可以看到,终结是正确的工具使用的情况相对较少。

    链接地址: http://www.djcxy.com/p/19909.html

    上一篇: Why would you ever implement finalize()?

    下一篇: How to test if a ThreadLocal has been initialized without actually doing that?