効果的な Java から:
ああ、もう 1 つ: ファイナライザーを使用すると、パフォーマンスが大幅に低下します。私のマシンでは、単純なオブジェクトの作成と破棄にかかる時間は約 5.6 ns です。ファイナライザーを追加すると、時間が 2,400 ns に増加します。つまり、ファイナライザーを使用してオブジェクトを作成および破棄すると、約 430 倍遅くなります。
ファイナライザーのコストが高い理由は何ですか?
決定的な違いは、それが何をするかに関係なく、ファイナライザー メソッドが存在することです。GC がファイナライズ可能なオブジェクトを持つとすぐに、すべてのハウスキーピングを正しく行うために、はるかに多くの作業を行う必要があります。それらをファイナライズ可能としてマークし、プールに保持し、ファイナライズを実行し、その後復活するかどうかを確認し、ファイナライズコードであらゆる種類のマルチスレッドの問題を処理する必要があります。
この違いは、GC の若い世代で最も顕著に見られます。楽観的であり、まったく珍しいシナリオではありませんが、GC は 1 つの操作に要約されます。つまり、最初に使用可能なメモリ アドレスへのポインターをデクリメントします。ファイナライザーの場合は、上で概説したプロセス全体です。
http://www.ibm.com/developerworks/java/library/j-jtp01274/index.html
上のリンクから抜粋
ファイナライザーを持つオブジェクト (重要な finalize() メソッドを持つオブジェクト) は、ファイナライザーを持たないオブジェクトと比較してかなりのオーバーヘッドがあるため、慎重に使用する必要があります。ファイナライズ可能なオブジェクトは、割り当てと収集の両方に時間がかかります。割り当て時に、JVM はファイナライズ可能なオブジェクトをガベージ コレクターに登録する必要があり、(少なくとも HotSpot JVM 実装では) ファイナライズ可能なオブジェクトは、他のほとんどのオブジェクトよりも遅い割り当てパスに従う必要があります。同様に、ファイナライズ可能なオブジェクトも収集に時間がかかります。ファイナライズ可能なオブジェクトを回収するには、ガベージ コレクション サイクルが少なくとも 2 回 (最良の場合) かかり、ガベージ コレクターはファイナライザーを呼び出すために余分な作業を行う必要があります。その結果、オブジェクトの割り当てと収集により多くの時間が費やされ、ガベージ コレクターにさらに負担がかかります。到達できないファイナライズ可能オブジェクトによって使用されるメモリがより長く保持されるためです。これを、ファイナライザーが予測可能な時間枠で実行されることが保証されていない、またはまったく実行されないという事実と組み合わせると、ファイナライズが適切なツールとして使用される状況は比較的少ないことがわかります。
ベンチマークするときは、おそらくオブジェクトの耐用年数をベンチマークします。
オブジェクトは耐用年数を超えて存在します。基本的に、最後のプログラム参照が消えてからガベージ コレクション ルーチン (別のスレッドで実行される) が切り離されたオブジェクトを検出するまでに時間の遅延があります。ファイナライザーを追加すると、ガベージ コレクションが切り離されたオブジェクトを検出し、JVM がファイナライズ メソッドを実行するまで、オブジェクトの「耐用年数」が延長されます。
ファイナライズによって非常に多くの時間が追加されるファイナライズ メソッドが存在するため、 100% ではありません。その多くの時間は、ガベージ コレクション スレッドがウェイクアップし、最終的にデタッチされたオブジェクトに遭遇するのを待っています (そして、それについて何かをすることを決定します)。