Finalizer是不可預知的,經常出問題的,而且是不必要的。使用它可能會導致不可預知的行為,性能降低和簡潔問題。C++需要析構函數釋放資源,Java是用垃圾回收器管理對象釋放。Java中一般在finally中是否其他資源。
finalizer的一個缺點是:不能保證他們在對象無用的時候立即執行。這就意味著不能在finalizer中做嚴格要求時間的事情。例如不要在finalizer中關閉文件。
finalizer的執行只是垃圾回收器算法的一個主要函數。每個JVM實現都會不同。
不要依賴finalizer來更新臨界持有狀態。例如不要在finalizer中釋放共享資源的持有鎖。
不要受System.gc和System.runFinalizerOnExit的誘惑.它們可能會增加finalizer執行的機會,但是不能保證。System.runFinalizerOnExit和Runtime.runFinalizersOnExit只是保證finalization。
使用finalizers會導致性能損失。在我的機器上創建和銷毀一個對象的時間是5.6ns,但是使用finalizer會增加時間到2400ns.
那么應該如何終止資源,例如文件和線程?如果僅僅是需要顯式的終止方法,那么可以使用InputStream和OutputStream和java.sql.Connection的Close方法。還有就是使用java.util.Timer的Cancel方法,對于java.awt使用Graphics.dispose和Window.dispose.
一般典型的顯式終止方法是包含在try-finally中來確保結束。例如
1
// try-finally block guarantees execution of termination method
2
Foo foo = new Foo(
);
3
try
{
4
// Do what must be done with foo
5

6
} finally
{
7
foo.terminate(); // Explicit termination method
8
}
四個類來作為顯示終止方法模式的例子:FileInputStream, FileOutputStream, Timer, and Connection。
使用finalizer的第二個合理對象是native peers。native peer是一個native對象它是通過native方法來代理正常的對象。由于native peer不是正常的對象,垃圾回收器無法知道它和在Java Peer回收的時候回收它。就需要finalizer來完成這個任務,來確保native peer不再持有臨界資源。
應該注意到,“finalizer chaining”不是自動完成的。如果一個類有一個finalizer,子類復寫了它。子類必須手動調用父類的finalizer。應該包含子類的finalizer在try中,將父類的finalizer放在finally中:
// Manual finalizer chaining

@Override protected void finalize() throws Throwable
{

try
{

// Finalize subclass state

} finally
{
super.finalize();
}
}
如果子類實現復寫了父類的finalizer,但是忘記了調用,父類的finalizer就不會被調用。
可以將finalizer放入一個匿名類中。匿名類的單實例叫做finalizer哨,被包含類為每個實例創建一個finalizer哨。
1
// Finalizer Guardian idiom
2
public class Foo
{
3
// Sole purpose of this object is to finalize outer Foo object
4
private final Object finalizerGuardian = new Object()
{
5
@Override protected void finalize() throws Throwable
{
6
// Finalize outer Foo object
7
}
8
};
9
// Remainder omitted
10
}
包含類存儲了一個私有單一引用在finalizer哨中。注意,Foo類不需要finalizer,因此不用擔心是否子類調用super.finalize.這種技術應該在每個具有finalizer的非final public 類中考慮。
總結:
不要使用finalizer,除非為了安全網或者終止非臨界native資源。在那些使用finalizer的極少的實例中,記住要調用super.finalize。如果使用finalize作為安全網,記住從finalizer中輸出無效用法的日志。最后,如果你需要關聯一個finalizer到public非靜態類中,考慮使用finalizer哨,它可以保證調用super.finalize失敗是還是可以finalization。
In summary, don’t use finalizers except as a safety net or to terminate
noncritical native resources. In those rare instances where you do use a finalizer,
remember to invoke super.finalize. If you use a finalizer as a safety net,
remember to log the invalid usage from the finalizer. Lastly, if you need to
associate a finalizer with a public, nonfinal class, consider using a finalizer
guardian, so finalization can take place even if a subclass finalizer fails to invoke
super.finalize.
posted on 2008-06-24 16:07
一葉笑天 閱讀(381)
評論(0) 編輯 收藏 所屬分類:
JAVA技術