我一直在阅读很多关于finalize()的Java新手问题,并发现没有人真正清楚地表明finalize()是一种不可靠的清理资源的方法,这有点令人困惑。我看到有人评论说他们用它来清理连接,这真的很可怕,因为唯一接近于保证连接关闭的方法是最后实现try (catch)。

我没有学过CS,但我已经用Java专业编程近十年了,我从来没有见过有人在生产系统中实现finalize()。这并不意味着它没有用处,或者和我一起工作的人一直在做正确的事情。

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

请提供具体的场景或您的经验,简单地重复Java教科书,或最终确定的预期用途是不够的,因为这不是这个问题的意图。


当前回答

您不应该依赖finalize()来为您清理资源。Finalize()在类被垃圾回收之前不会运行。在使用完资源后显式地释放资源要好得多。

其他回答

Be careful about what you do in a finalize(). Especially if you are using it for things like calling close() to ensure that resources are cleaned up. We ran into several situations where we had JNI libraries linked in to the running java code, and in any circumstances where we used finalize() to invoke JNI methods, we would get very bad java heap corruption. The corruption was not caused by the underlying JNI code itself, all of the memory traces were fine in the native libraries. It was just the fact that we were calling JNI methods from the finalize() at all.

这是JDK 1.5,它仍然在广泛使用。

直到很久以后,我们才发现出了问题,但最终罪魁祸首始终是使用JNI调用的finalize()方法。

我在生产代码中使用finalize的唯一一次是执行一个检查,检查给定对象的资源是否已被清理,如果没有,则记录一个非常明显的消息。它实际上并没有尝试自己去做,如果做得不好,它就会大喊大叫。结果很有用。

接受的答案列出了在finalize期间关闭资源的操作。

然而,这个答案表明,至少在使用JIT编译器的java8中,您会遇到意想不到的问题,有时甚至在您完成从对象维护的流中读取之前就调用了终结器。

所以即使在这种情况下,也不建议调用finalize。

您可以将它用作持有外部资源(套接字、文件等)的对象的支持。实现close()方法和需要调用它的文档。

如果检测到close()没有执行,则实现finalize()来执行close()处理。可能会将一些东西转储到stderr,以指出您正在清理有错误的调用者。

它在异常/有bug的情况下提供了额外的安全性。并不是每个调用者每次都会执行正确的try {} finally{}。不幸的是,但在大多数环境中都是如此。

我同意很少有人需要它。正如评论者指出的那样,它带来了GC开销。只有当你在一个长期运行的应用程序中需要“皮带和背带裤”的安全性时才使用。

我看到从Java 9开始,Object.finalize()已弃用!它们将我们指向java.lang.ref.Cleaner和java.lang.ref.PhantomReference作为替代。

我不知道你是怎么想的,但是…

itsadok@laptop ~/jdk1.6.0_02/src/
$ find . -name "*.java" | xargs grep "void finalize()" | wc -l
41

所以我猜《太阳报》找到了一些(他们认为)应该使用它的案例。