终结方法(finalizer)通常是不可预测的,也是很危险的,一般情况下是不必要的。使用终结方法会导致行为不稳定、降低性能,以及可移植性问题。
在Java中完成这样的工作主要是依靠try-finally机制来协助完成的,然而Java中还提供了另外一种被称为finalizer的机制,使用者仅仅需要重载Object对象提供的finalize方法,这样当JVM的在进行垃圾回收时,就可以自动调用该方法。但是由于对象何时被垃圾收集的不确定性,以及finalizer给GC带来的性能上的影响,因此并不推荐使用者依靠该方法来达到关键资源释放的目的。比如,有数千个图形句柄都在等待被终结和回收,可惜的是执行终结方法的线程优先级要低于普通的工作者线程,这样就会有大量的图形句柄资源停留在finalizer的队列中而不能被及时的释放,最终导致了系统运行效率的下降,甚至还会引发JVM报出OutOfMemoryError的错误。
Java的语言规范中并没有保证该方法会被及时的执行,甚至都没有保证一定会被执行。即便开发者在code中手工调用了
System.gc 和 System.runFinalization 这两个方法,这仅仅是提高了finalizer被执行的几率而已。还有一点需要注意的是,被重载的finalize()方法中如果抛出异常,其栈帧轨迹是不会被打印出来的。在Java中被推荐的资源释放方法为,提供显式的具有良好命名的接口方法,如
FileInputStream.close() 和 Graphic2D.dispose() 等。然后使用者在finally区块中调用该方法,见如下代码:
public void test() { FileInputStream fin = null; try { fin = new FileInputStream(filename); //do something. } finally { fin.close(); } }
在实际的开发中,利用finalizer又能给我们带来什么样的帮助呢?见下例:
public class FinalizeTest { //@Override protected void finalize() throws Throwable { try { //在调试过程中通过该方法,打印对象在被收集前的各种状态, //如判断是否仍有资源未被释放,或者是否有状态不一致的现象存在。 //推荐将该finalize方法设计成仅在debug状态下可用,而在release //下该方法并不存在,以避免其对运行时效率的影响。 System.out.println("The current status: " + _myStatus); } finally { //在finally中对超类finalize方法的调用是必须的,这样可以保证整个class继承 //体系中的finalize链都被执行。 super.finalize(); } } }
时间: 2024-10-17 11:37:30