• 问题

    finalize()通常是不可预测的,也是很危险的,一般情况下也是不必要的。使用finalize()会导致行为不稳定、降低性能,以及可移植性的问题。虽然终结方法也有可用之处,但是还是应该避免使用它,finalize()方法的缺点和用途有哪些?

  • 解决

    finalize()方法的缺点:

    1. finalize()方法的缺点在于不能保证会及时的执行。从一个对象变成不可达开始,到它的终结方法被执行,所花费的时间是任意长的。这意味着,注重时间的任务不应该由finalize()方法来完成。例如,使用finalize()方法来关闭已经打开的文件,这就是十分严重的错误。因此,不应该以来finalize()方法来更新重要的持久状态。还有一点,使用finalize()方法有非常严重的性能损失;
    2. 为类提供finalize()方法,可能会随意地延迟其实例的回收过程。如果对象进入F-Queue队列速度大于出队速度的话,就会造成大量对象没有被及时回收;
    3. JAVA的语言规范不仅不保证终结方法被及时执行,而且根本就不保证它们会被执行。当一个程序终结的时候,某些已经无法访问的对象上的终结方法却根本没有被执行,这是完全可能的。这里得到的结论就是:不应该依赖终结方法来更新重要的持久状态。例如,依赖终结方法来释放共享资源(比如,数据库)上的永久锁,很容易让整个分布式系统跨掉。
    4. 及时的执行finalize方法是垃圾回收过程中一个重要步骤,这种算法在不同的JVM实现平台上会有很大的差别,也许在测试的JVM平台上测试性能良好,却可能在其他平台上的性能很差。

    finalize方法有这样的两个用途:

    1. 如果对象的所有者忘记显示关闭对象(如文件流,数据库session等),可使用finalize()方法作为最后的兜底,虽然这样做并不能保证终结方法能被及时的调用,但是在客户端无法通过调用显式的终结方法来正常结束操作的情况下,晚一点释放总比不释放的好。但是如果终结方法发现资源还未被终止,应该在日志中记录一条日志信息,因为这表明客户端代码中的一个bug,应该得到修复;
    2. 第二种合理用途与对象的本地对等体(natvie peer)有关。本地对等体是一个本地对象,普通对象通过本地方法委托给一个本地对象,因为本地对等体不是一个普通的对象,所以垃圾回收器并不知道它,当它的java对等体被回收的时候,它却不会被回收掉。在本地对等体并不拥有关键资源的前提下,终结方法正好被用来执行回收本地对等体。
  • 结论

    除非使用finalze()来作为回收对象最后的兜底操作,就不要使用finalize()方法。如果使用了finalize()方法就要调用super.finalize,并且要在日志上记录使用了finalize()的特殊情况,应该当做Bug去修复。

results matching ""

    No results matching ""