清理finalize()或finally()中的代码?
我普遍认为清理资源是在finally
块中完成的,
最近我在类中找到了这个特定的代码片段,它覆盖了Object
类的finalize()
方法。
protected void finalize() { try { In.close(); Out.close(); socket.close(); } catch (Exception e) { //logger code here } }
这是一个好主意吗? finalize()
finally
优缺点是什么?
finally
块只是一个代码块,它总是在try
块之后执行,即使有exception也是如此。 即它在本地范围内
finalize()
方法是一种在垃圾收集时清理整个对象的方法。
finalize()的Java文档
无论是否出现exception情况, finally
解决了清理代码块中资源的问题…一旦垃圾收集器确定不存在,当终止对象时, finalize()
是一种清理资源的方法更多对该对象的引用。
简而言之,要回答你的问题,例如,如果你要关闭的套接字是一个对象的成员,你应该在finalize()
方法中关闭它们(虽然这是次优的,例如,因为不能保证当GC实际执行动作时)
但是,如果您在方法中打开套接字,并且在方法结束时使用它完成,则应释放finally
块中的资源。
总是在最后清理东西。
无法保证最终完成清理。
然而,经常发现在终结器中清理这样的东西作为最后一个安全阀应该最终阻止另外一个例外。
依赖于终结器的真正问题是在GC调用终结器之前可能需要资源的其他东西。
幻影参考将做你想要的。
只是不要使用finalize。 有一些边缘情况可能会有所帮助(当一个类是GC的时候打印调试信息已经派上用场了),但通常不会。 JVM合同中没有任何内容甚至说它必须被调用。
有一种非常不公开的对象称为“引用”。 一个是明确的,你认为你会使用finalize的东西。
“ 幻影参考对象,在收集者确定他们的指示物可能被收回后排队。”
我刚刚想到网上必须有这样的描述 -所以我将用这个参考替换我刚写的所有“操作方法”。
他们没有关系。 这就像问:“你应该在初始化器或普通方法中创建对象吗?” 比如,它取决于你对物体做了什么。 终结器在它被销毁时清除对象的状态(可能 – 它不是你应该依赖的东西),而finally块在try块之后执行代码。 没有任何常见的情况,你可以选择其中一个,因为他们做了不同的事情。
如果您的应用程序导致创建了大量这些对象,那么Finalize可能是一个坏主意。 这是因为当对象符合垃圾收集条件时,finalize将导致瓶颈。
有时候终结是唯一的解决方案; 但是无论何时你都可以使用
最后。 敲定很糟糕,因为它可能永远不会被调用。 仅将finalize用作安全网。 例如,一个InputStream应该有一个finalize,用于关闭流,以及applcicationforgets。 但是应用程序应该关闭它。
如果是我,我也会在终结器中进行清理,并在执行清理时记录案例,然后在应用程序中跟踪忘记正确清理的代码。
问题中的代码存在许多问题,包括:
- 最大的问题:看起来你正试图关闭套接字。 即使你没有正确关闭它,它也会在它自己的终结器中关闭。 添加另一个终结器并不会使它更加封闭。
- 第一次
close
抛出的exception将阻止其他人执行(因为在这个例子中,由于Socket
的特殊行为,这无关紧要)。 - 如果你确实覆盖了
finalize
,那么让它抛出Throwable
(并添加@Override)。 从技术上讲,你也应该在finally块中调用super。 - 对于终结者来说,Java内存模型非常奇怪(以前的代码执行不一定会在执行终结器之前发生 )。 我会解释这个问题,但你需要知道的是你需要远离终结者。
所以:总是finally
使用这些东西。 finalize
是非常专业的(而PhantomReference
可能更好,表面上更复杂)。
如果您正在寻找finalize()
的替代方案,那么正确的问题是:
- 为什么使用显式的
close()
方法,例如java.io. *中的所有流和writer / reader类以及许多其他类 – 当有finalize()
?
其他答案清楚地表明, finalize()
的缺点是你没有办法强制它运行,也没有人可能会使用你的代码。
当然,调用close()
方法(最好在finally
块或close()
方法本身中完成)必须由作者记录,然后记住由使用代码的人调用。 但是有很多例子(不仅是java.io.*
),这是强制实施的。
BTW: close()
仅仅是一个惯例。
Joshua Bloch在他的“ Effective Java(第2版)”一书中提出了一个非常明确的建议。 复制自第2章第7项:避免终结者 :
终结器是不可预测的,通常是危险的,并且通常是不必要的。 它们的使用会导致不稳定的行为,性能不佳和可移植性问题。 终结器有一些有效的用途,我们将在本项后面介绍,但根据经验,你应该避免使用终结器。
请阅读参考资料以了解原因。
- Calendar.getInstance()。getTime()是否会给我一个与新Date()不同的答案?
- Android getExternalStorageDirectory不会返回任何文件
- “就地”EditTextPreference
- 如何配置嵌入式jetty服务器以记录所有请求?
- 说“Java Modified UTF-8 Encoding”是什么意思?
- 模拟android.content.res.Configuration类型的对象并为其指定一个语言环境
- Hung JVM消耗100%的CPU
- Java ProcessBuilder process.destroy()不会在winXP中杀死子进程
- 用于自动资源释放的java技术? “迅速清理”?