以下は、 Effective Java 2nd Editionからの引用の一部です: 項目 7: ファイナライザーを避ける:
ファイナライザは予測不可能で、危険な場合が多く、一般的に不要です。それらを使用すると、動作が不安定になり、パフォーマンスが低下し、移植性の問題が発生する可能性があります。ファイナライザーの有効な用途はほとんどありません。[...]経験則として、ファイナライザーは避けるべきです。
実際、ファイナライザーが必要であることを本当に確認する必要があります。ほとんどの場合、あなたはしません。
C++ プログラマは、ファイナライザを Java の C++ デストラクタの類似物と考えないように注意してください。C++ では、デストラクタはオブジェクトに関連付けられたリソースを再利用する通常の方法であり、コンストラクタに必要な対応物です。Java では、ガベージ コレクターは、到達不能になったオブジェクトに関連付けられたストレージを再利用するため、プログラマー側で特別な作業を行う必要はありません。C++ デストラクタは、他の非メモリ リソースを再利用するためにも使用されます。Java では、try-finally
一般にこの目的でブロックが使用されます。
ファイナライザーが呼び出されるときのセマンティクスも考慮することが重要です。
Java プログラミング言語では、finalizer
が呼び出されるまでの時間 [...または] 特定のオブジェクトのファイナライザーを呼び出すスレッドを指定しません。[...] ファイナライズ中にキャッチされない例外がスローされた場合、例外は無視され、そのオブジェクトのファイナライズは終了します。(JLS 12.6.2) ファイナライザーの呼び出しが順序付けされていない
さらに、オンデマンドでファイナライザーを実行する唯一のメカニズムが壊れています。以下の引用は、Effective Java 2nd Edition からのものです。
[...] ファイナライズを保証すると主張する唯一の方法はSystem.runFinalizersOnExit
、 とその邪悪な双子ですRuntime.runFinalizersOnExit
。これらのメソッドには致命的な欠陥があり、推奨されていません。
Bloch は、パフォーマンスのペナルティについてさらにコメントしました (彼を強調してください)。
ああ、もう 1 つあります。ファイナライザーを使用すると、パフォーマンスが大幅に低下します。私のマシンでは、単純なオブジェクトの作成と破棄にかかる時間は約 5.6ns です。ファイナライザーを追加すると、時間が 2,400ns に増加します。つまり、ファイナライザーを使用してオブジェクトを作成および破棄すると、約 430 倍遅くなります。
ベンチマークの方法論に関する詳細がほとんどないため、特定の数値はあまり意味がないと思いますが、広く文書化されていることを裏付けています。ファイナライザーは非常にコストがかかります。
この本では、ファイナライザーの使用が有効なまれなシナリオについて説明しています。この回答からの引用の省略は意図的なものです。