清理finalize()或finally()中的代码?

时间:2009-12-03 23:43:54

标签: java

我普遍认为清理资源是在finally区块中完成的 最近我在一个类中找到了这个特定的代码段,它覆盖了Object类'finalize()方法。

protected void finalize() {  
    try {
        In.close(); 
        Out.close();
        socket.close();
    }
    catch (Exception e) {
        //logger code here
    }
}

这是个好主意吗? finalize()超过finally的优缺点是什么?

9 个答案:

答案 0 :(得分:16)

finally块只是一个代码块,它始终在try块之后执行,即使存在异常。即它在本地范围内

finalize()方法是一种在垃圾收集时清理整个对象的方法。

Java documentation of finalize()

finally解决了清除代码块中资源的问题,无论是否出现异常情况...... {Garler Collecter确定不再有对该对象的引用时,finalize()是一种在不再使用对象时清理资源的方法。

简而言之,要回答你的问题,例如,如果你要关闭的套接字是一个对象的成员,你应该用finalize()方法关闭它们(虽然这是次优的,仅举例来说,因为无法保证GC何时会实际执行此操作)

但是,如果您在方法中打开套接字,并且在方法结束时使用它完成,则应释放finally块中的资源。

答案 1 :(得分:8)

最后总是清理东西。

不保证最终确定清理。

然而,经常发现在终结器中清理这些东西作为最后一个安全阀应该最终阻止你再发一个例外。

依赖终结器的真正问题是在GC调用终结器之前可能还需要资源。

答案 2 :(得分:5)

Phantom References会做你想要的。

只是不要使用finalize。有一些边缘情况可能会有所帮助(当一个类GCd已经派上用场时打印调试信息),但通常不会。 JVM合同中没有任何内容甚至说它必须被调用。

有一种非常不公开的对象称为“引用”。一个是明确的,你认为你会使用finalize for。

Phantom reference个对象,在收集者确定他们的指示物可能被收回后排队。”

我刚想到必须有a description of this on the web - 所以我会用这个参考替换我刚写的所有“操作方法”。

答案 3 :(得分:4)

他们没有关系。这就像问:“你应该在初始化器或普通方法中创建对象吗?”比如,它取决于你对对象做了什么。终结器在它被销毁时清除对象的状态(可能 - 它不是你应该依赖的东西),而finally块在try块之后执行代码。没有任何常见的情况,你可以选择其中一个,因为他们做了不同的事情。

答案 4 :(得分:2)

如果您的应用程序导致创建了大量这些对象,那么Finalize可能是一个坏主意。这是因为finalize会导致瓶颈,因为对象有资格进行垃圾回收。

有时候终结是唯一的解决方案;但是无论什么时候都可以使用

答案 5 :(得分:2)

最后。敲定很糟糕,因为它可能永远不会被调用。使用finalize仅作为安全网。例如,一个InputStream应该有一个finalize,用于关闭流,以及applcicationforgets。但应用程序应关闭它。

如果是我,我也会在终结器中进行清理,并在执行清理时记录案例,然后在应用程序中追踪忘记正确清理的代码。

答案 6 :(得分:1)

问题中的代码存在许多问题,包括:

  • 最大的问题:看起来你正试图关闭套接字。即使你没有正确关闭它,它也会在自己的终结器中关闭。添加另一个终结器不会让它更加封闭。
  • 第一个close引发的异常将阻止其他人执行(因为Socket的特殊行为,在本例中这无关紧要。
  • 如果您覆盖finalize,请将其抛出Throwable(并添加@Override)。从技术上讲,你也应该在一个finally块中调用super。
  • 对于终结者而言,Java内存模型非常奇怪(以前执行代码不一定执行终结者之前发生)。我会解释这个问题,但你需要知道的是你需要远离终结者。

所以:总是使用finally来做这些事情。 finalize非常专业(PhantomReference可能更好,表面上更复杂)。

答案 7 :(得分:0)

如果您正在寻找finalize()的替代方案,那么正确的问题将是:

  • 为什么使用显式的close()方法,例如,java.io。*中的所有流和编写器/阅读器类以及许多其他类 - 当有finalize()时?

其他答案清楚地表明finalize()的缺点是您无法强制它运行,也没有人可能会使用您的代码。

当然,调用close()方法(最好在finally块或close()方法中完成)必须由作者记录,然后记住要调用那些使用代码的人。但是有很多例子(不仅是java.io.*)强加给它并且有效。

BTW:close()仅仅是一种惯例。

答案 8 :(得分:0)

Joshua Bloch在他的书Effective Java (2nd Edition)中提出了一个非常明确的建议。复制自第2章Item 7: Avoid finalizers

  

终结器是不可预测的,通常是危险的,而且通常是不必要的。它们的使用会导致不稳定的行为,性能不佳和可移植性问题。终结器有一些有效用途,我们将在本项后面介绍,但根据经验,你应该避免使用终结器。

请阅读参考资料以了解原因。