m88体育 避免使用finalizer
Java语言规范里没有要求finalizer何时被执行,甚至没要求它一定要被执行。各种不同的jvm实现完全可能以它们自己的方式来处理finalizer,所以finalizer里的代码执行没有任何保障,从这点上来说,很多c++程序员把finalizer作为c++析构函数在Java中的对应功能是完全错误的。如果错误地依赖finalizer来释放被占用的资源或者执行某些时序任务,很可能会造成不可预料的错误行为。
Java面试里面一个烂大街的问题就是System.gc()方法有什么作用,其实还有一个类似的方法System.runFinalization(),两者没太大区别,都是向jvm提出gc请求,但根本无法保证jvm会及时作出响应。当然,这两个方法还是提高了finalizer被执行的可能性。
finalizer的另一个问题是异常处理。当其中的代码抛出异常时,如果没有显式定义catch处理,这些异常将被完全忽略,所在线程会瞬间终止,连stack trace都不会打印。
最后,finalizer会造成严重的性能损失。比如正常情况下销毁一个简单对象耗时5.6ns,定义一个finalizer之后,这个耗时会增加到2400ns,变慢了430倍。
Java中正确释放资源的方法,m88体育 应该是显式定义一个terminate方法,并在finally模块中调用它。而且,最好在此方法中将对象状态定义为"已终止",以避免不恰当地使用不完整对象:
// try-finally block guarantees execution of termination method Foo foo = new Foo(...); try { // Do what must be done with foo ... } finally { foo.terminate(); // Explicit termination method }
只有两种情况下需要使用finalizer方法:
1、作为显式terminate方法的双保险
2、涉及到本地对象(native object)的释放
在真正使用finalizer的场合,需要注意finalizer方法不像构造函数那样有chaining,也就是说,在一个子类覆盖了父类的finalizer时,必须显式调用super.finalize(),否则后者不会被自动执行:
// Manual finalizer chaining @Override protected void finalize() throws Throwable { try { ... // Finalize subclass state } finally { super.finalize(); } }
还有一种解决方法是finalizer guardian:
// Finalizer Guardian idiom public class Foo { // Sole purpose of this object is to finalize outer Foo object private final Object finalizerGuardian = new Object() { @Override protected void finalize() throws Throwable { ... // Finalize outer Foo object } }; ... // Remainder omitted }
当Foo子类的一个对象被终结时,finalizerGuardian作为它的一个成员也会被终结,其覆盖的finalize()方法会被调用,所以不管Foo的子类是否显式调用了super.finalize(),Foo都会被妥善终结。