【问题标题】:Is there any need for java's finalize method?需要java的finalize方法吗?
【发布时间】:2016-06-10 13:20:07
【问题描述】:

我读过的关于 java finalize 方法的所有内容都说 NOT 使用它。似乎它几乎永远不能保证会被调用,即使被调用也可能会出现问题。

还有一些其他问题询问何时使用它,似乎普遍的共识是从不

我自己从未使用过它(主要是因为警告不要使用),我也没有看到它在任何地方使用过。

有没有合适的情况?有没有其他选择的情况?

如果没有,为什么会出现?是否有内部类使用它并要求该方法可用?还是它只是不应该存在的东西?

我对什么时候应该使用它不太感兴趣(已回答“从不”),但在给出“从不”的答案时澄清为什么它甚至在那里。既然这么没用又这么危险,为什么不被贬值和淘汰呢?

【问题讨论】:

  • @Alex 我的问题很相似,但我认为它并不完全相同。我并没有问那么多为什么我会使用它(我不应该),而是为什么它首先存在(考虑到我不应该)。 java API 是否出于某种原因需要它?出于某种原因,JVM 是否必须在所有对象上查看该方法?或者是否存在根本没有其他选择的情况? (其中第三个由您链接的问题解决,但前两个不是)。
  • @Alex 我编辑了我的标题以使这种区别更加清晰。
  • 好吧,JLS 要求它存在,但给出的唯一原因是 Finalizer 提供了释放自动存储管理器无法自动释放的资源的机会。在这种情况下,简单地回收一个对象使用的内存并不能保证它所持有的资源会被回收。 finalize 的 javadoc 还说 finalize 的通常目的是执行清理操作在对象被不可撤销地丢弃之前。我不知道创建它的另一个原因。

标签: java finalize


【解决方案1】:

向后兼容性。有人首先认为这是一个好主意,然后当全世界意识到这不是一个好主意时,为时已晚。

这些东西几乎没有被移除。 Java 充满了现在被认为是坏主意但仍然没有被删除的概念——我想到的更多例子是clone()Thread.stop()

【讨论】:

  • 是否有人推荐它,或者早期的垃圾收集器在运行它时更可靠?似乎它不应该抓住问题。如果它没有流行起来,似乎删除它应该更安全。我知道 java 喜欢贬值,但仍然不删除它们。有什么理由至少没有贬值吗?
  • 我不认为他们过去更可靠。随着人们试图使用它,一些危险随着时间的推移而为人所知。更多的不可靠性可能来自今天的 JAva GCing 较少(由于更多的内存和尽可能延迟 GC 的策略)。
  • 我的理解是,finally() 主要是为了允许释放不受 GC 控制的资源,它们的释放并不重要(即如果 JVM 关闭,它们'将被自动释放)——比如在使用非 Java 组件、DLL 等时通过一些本机代码分配内存。
  • 好的,该评论很有帮助。这与@MartinS 的回答类似,但区分非关键免费资源似乎更好用。使用它来摆脱我想要恢复的内存但如果 JVM 关闭不会使系统处于某种可怕状态的资源似乎更安全。
  • @Matthew 我提到的示例也将被视为非关键资源。即使 JVM 不控制内存,如果 JVM 关闭,它仍然会被操作系统释放。只是您不想在长时间运行的程序中出现内存泄漏:)
【解决方案2】:

您可能会使用它并且可以接受的一个用例是释放不受 JVM 控制的资源,即否则不会被释放的资源。例如,使用sun.misc.Unsafe(*) 分配的内存必须手动释放,因为它不会被垃圾回收。因此,如果之前没有释放内存,您可以使用finalize 方法作为释放内存的最后手段——只是为了确保您的程序没有内存泄漏。但这些情况相当罕见,如今 Java 提供了更好的替代方案,例如 Java 7 中引入的 AutoClosable 接口。

您可以在 OpenJDK 源代码中找到更多示例,例如 FileInputStream 使用 finalize 方法来确保它已关闭。

(*) 不要使用它,它被称为Unsafe 是有原因的。

编辑:回答您评论中的问题

java API 是否出于某种原因需要它?

是和不是。 Java Language Specification 声明它必须存在。 Java 库中的某些类也使用它(例如,当它们处理文件时),但没有 Java API 要求您为您的类实现它。

JVM 是否出于某种原因必须在所有对象上查看该方法?

好吧,又是这样,因为 JLS 是这么说的,垃圾收集器会为它收集的每个对象调用它。

当垃圾收集器确定不再有对该对象的引用时,由垃圾收集器对该对象调用。

但它确实在 Object implements it 之后的所有对象上看到了 finalize 方法 - 默认情况下它什么也不做。

protected void finalize() throws Throwable { }

【讨论】:

  • 我明白你为什么会在这种情况下考虑它,但鉴于不能保证它会运行,你会依赖它来释放这些资源吗?我还没有真正做过类似的事情,但鉴于其不可预测性,这些资源似乎仍然很有可能无法正确释放。
  • 这就是为什么我说“作为最后的手段”。当程序员忘记在某处释放资源时,这仍然比什么都不做要好,因为您至少很有可能最终会调用finalize
猜你喜欢
  • 2015-06-28
  • 2013-09-20
  • 2011-06-05
  • 2011-07-07
  • 2011-03-19
  • 2015-03-13
  • 2011-08-17
  • 2019-04-10
  • 2018-12-03
相关资源
最近更新 更多