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

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

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

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


当前回答

就我个人而言,除了在一种罕见的情况下,我几乎从不使用finalize():我创建了一个自定义泛型类型集合,并编写了一个自定义finalize()方法,它执行以下操作:

public void finalize() throws Throwable {
    super.finalize();
    if (destructiveFinalize) {
        T item;
        for (int i = 0, l = length(); i < l; i++) {
            item = get(i);
            if (item == null) {
                continue;
            }
            if (item instanceof Window) {
                ((Window) get(i)).dispose();
            }
            if (item instanceof CompleteObject) {
                ((CompleteObject) get(i)).finalize();
            }
            set(i, null);
        }
    }
}

(CompleteObject是我做的一个接口,让你指定你已经实现了很少实现的对象方法,如#finalize(), #hashCode()和#clone()))

因此,使用姐妹方法# setdestructivelyfinalizer(布尔值),使用我的集合的程序可以(帮助)确保销毁对该集合的引用也会销毁对其内容的引用,并处理可能在无意中保持JVM活动的任何窗口。我也考虑过停止任何线程,但这打开了一个全新的蠕虫罐头。

其他回答

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()的好例子,那是一个缓存,在它被销毁之前将其内容写入磁盘。因为它没有必要在每次销毁时都执行,它只会加速我的程序,我希望我没有做错。

@Override
public void finalize()
{
    try {saveCache();} catch (Exception e)  {e.printStackTrace();}
}

public void saveCache() throws FileNotFoundException, IOException
{
    ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("temp/cache.tmp"));
    out.writeObject(cache);
}

嗯,我曾经用它来清理没有返回到现有池的对象。

它们经常被转来转去,所以不可能知道什么时候能安全地放回泳池。问题在于,它在垃圾收集过程中带来了巨大的损失,远远超过了使用对象池节省的成本。在我拆除整个池,让所有内容都变得动态并完成之前,它已经投入了大约一个月的时间。

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

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

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

作为旁注:

覆盖finalize()的对象由垃圾回收器进行特殊处理。通常,在对象不再在作用域中后,在收集周期中立即销毁对象。但是,可终结对象被移到队列中,在队列中,独立的终结线程将耗尽队列并在每个对象上运行finalize()方法。一旦finalize()方法终止,对象就可以在下一个循环中进行垃圾收集了。

源代码:finalize()在java-9上已弃用