Java的finalize方法有必要吗?

6
我所阅读的有关Java finalize方法的所有内容都说不要使用它。似乎它几乎从来没有保证被调用,并且即使在使用时也可能会出现问题。
还有一些其他的问题问到何时使用它,总体上的共识是永远不要使用
我自己从未使用过它(主要是因为警告不要使用它),而且我也没有看到它在任何地方被使用。
是否有任何情况下适合使用它?是否有没有替代方案的情况?
如果没有,请问它存在的目的是什么?是否有内部类使用它并需要该方法可用?还是说它只是一个不应存在的东西?
我对何时应该使用它不是很感兴趣(已经回答过“永远不要使用”),但需要澄清的是,既然已经回答了“永远不要使用”,那么为什么它还存在?如果它如此无用和危险,为什么它没有被弃用和删除?

https://dev59.com/NnVC5IYBdhLWcg3w4VRz - Alex - GlassEditor.com
@Alex 我的问题类似,但我认为它并不完全相同。我问的不是为什么我会使用它(我不应该),而是为什么它首先存在(考虑到我不应该使用它)。Java API是否需要它出于某种原因?JVM是否必须在所有对象上看到该方法出于某种原因?还是有时根本没有其他选择?(第三个问题已在您链接的问题中得到解决,但前两个问题尚未解决)。 - Matthew
@Alex,我编辑了我的标题,以使这个区别更加清晰。 - Matthew
好的,JLS要求它存在,但唯一给出的原因是“Finalizers提供了一个机会来释放那些不能被自动存储管理器自动释放的资源。在这种情况下,仅回收对象使用的内存并不能保证它所持有的资源会被回收。” finalize的javadoc也说“finalize的通常目的是在对象被不可撤销地丢弃之前执行清理操作”。我不知道它被创建的另一个原因。 - Alex - GlassEditor.com
2个回答

3

向后兼容性。有人最初认为这是一个好主意,当世界意识到这不是一个好主意时,已经太晚了。

这些东西几乎从未被删除。Java充满了现在被认为是不好的概念,但仍未被删除的一些例子,我脑海中想到的更多例子包括clone()Thread.stop()


有没有一个时间点它被推荐使用过,还是早期的垃圾回收器在运行它时更可靠?看起来它不应该在存在问题的情况下流行起来。如果它没有流行起来,似乎将其删除应该更安全。我知道java喜欢废弃某些东西但仍不会将它们删除。它至少为什么没有被标记为过时? - Matthew
1
我认为它们曾经更加可靠。随着人们尝试使用它,一些危险逐渐被发现。由于更多的内存和尽可能延迟GC策略,今天的Java GC可能会更加不可靠。 - Jiri Tousek
1
我的理解是,finally() 主要用于释放那些不受 GC 控制且释放不是关键的资源(即使 JVM 关闭,它们也会被自动释放)- 比如在使用非 Java 组件、DLL 等时通过某些本地代码分配内存。 - Jiri Tousek
好的,那个评论很有帮助。这与@MartinS的回答类似,但是不关键的免费资源的区别似乎更好地利用了它。将其用于摆脱我想要回收内存但如果JVM关闭不会使系统处于某种可怕状态的资源似乎是更安全的用法。 - Matthew
1
@Matthew,我提到的例子也将被视为非关键资源。即使JVM不控制内存,如果JVM关闭,操作系统仍将释放它。只是你不想在长时间运行的程序中出现内存泄漏 :) - MartinS

2
一种可能使用并且可接受的情况是释放不受JVM控制的资源,即否则不会被释放的资源。例如,使用sun.misc.Unsafe分配的内存必须手动释放,因为它不会被垃圾回收。因此,如果之前没有被释放,您可以使用finalize方法作为最后的手段来释放内存,以确保您的程序没有内存泄漏。但这些情况相当少见,今天Java提供了更好的替代方案,如在Java 7中引入的AutoClosable接口。
你可以在OpenJDK源代码中找到更多的例子,例如{{link1:FileInputStream}}使用finalize方法确保它已关闭。
(*) 不要使用它,它被称为Unsafe有原因。
编辑:回答您评论中的问题
Java API是否需要它?
是和不是。Java语言规范(Java Language Specification)规定它必须存在。此外,一些在Java库中使用它的类(例如处理文件时)但没有Java API需要你为你的类实现它。
JVM是否必须在所有对象上看到该方法呢?
是的,因为JLS这样规定,垃圾回收器会在每个它回收的对象上调用它。
但是它确实在所有对象上看到finalize方法,因为Objectimplements it,默认情况下它什么也不做。
protected void finalize() throws Throwable { }

我能理解你在这种情况下考虑这样做的原因,但是考虑到没有保证它会运行,你是否想要依赖它来释放那些资源呢?我并没有真正做过类似的事情,但看起来由于其不可预测性,仍然存在很大的可能性那些资源不会被正确释放。 - Matthew
1
这就是我为什么说“最后的办法”,因为当程序员在某个地方忘记释放资源时,这仍然比什么都不做要好,因为您至少有很大的机会最终调用finalize - MartinS

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接