Effective Java Item7-不使用Finalizers

Effective Java 2nd Edition Reading Notes

Item7: Avoid Finalizers

不使用Finalizers

 

Finalizers是不可预知的,有时是危险的,并且是不必要的。

C++中,析构函数用于回收资源,而在Java中,通过GC来回收资源。析构函数还用于回收非内存资源,在Java中,通过try{}finally{}来完成同样的工作。

 

首先finalizers并不能保证被马上执行。在对象不可用开始到finalize方法执行之间的时间是任意的。这意味着不能在finalizers中进行具有时间要求的操作。例如在finalizer中关闭文件。[操作系统中可以打开的文件数是有限制的,一旦超过限制,将不能再打开文件。]

何时执行finalizersGC的功能,因JVM的实现不同而不同。使用finalizers在极端的情况下会导致实例回收的延迟,从而发生OutOfMemoryError。规范没有定义finalizers什么时候执行,甚至不能确保finalizers是否会被执行。

永远不要依赖finalizers去实现持久性的更新。例如在finalizers中释放持久性的锁。

 

不要使用System.gc或者System.runFinalization,它们导致finalizers的运行怪异,并且不提供任何保障。

另外,如果未捕获的异常发生在finalizers中,那么异常被忽略(不输出任何信息)finalizer将终止。

同时,使用finalizers会带来严重的性能影响。

Oh, and one more thing:  there is a  severe performance penalty for using finalizers. On my machine, the time to create and destroy a simple object is about 5.6 ns. Adding a finalizer increases the time to 2,400 ns. In other words, it is about 430 times slower to create and destroy objects with finalizers.

 

进行finalize的一个好的办法是提供一个显式的终止方法,同时记录实例的状态,例如提供一个成员变量来记录,在使用其他方法的时候,检查该成员变量的值。如果实例已经被终止,那么抛出IllegalStateException。比较典型的是java.sql.Connection, java.io.InputStream, java.io.OutputStream, java.util.Timer等等。

显式的终止方法通常和try{}finally{}结合使用,在finally中调用终止方法来终止对象。

 

finalizer的实际作用:

Finalizer的一个作用是提供一个Safety net,即万一客户端,例如使用InputStream的其他类忘记关闭流,那么通过finalize方法来关闭,但是最好应该在finalize方法中提供日志输出,提示客户端错误。

例如FileOutputStreamfinalize方法如下:

/**

     * Cleans up the connection to the file, and ensures that the

     * <code>close</code> method of this file output stream is

     * called when there are no more references to this stream.

     *

     * @exception  IOException  if an I/O error occurs.

     * @see        java.io.FileInputStream#close()

     */

    protected void finalize() throws IOException {

       if (fd != null) {

           if (fd == fd.out || fd == fd.err) {

              flush();

           } else {

              close();

           }

       }

    }

Finalizer的另一个作用适用于本地对等对象(java对象通过本地对等对象获取),由于native peer不是java实例,所以GC不会回收对等对象。此时提供finalizer来回收该对象。

你可能感兴趣的:(java,exception,Stream,File,performance)