7

この投稿によると、.Netでは、

ファイナライザーは実際にはそれよりもさらに悪いです。それらは遅く実行されることに加えて (実際、多くの種類のリソースにとって深刻な問題です)、デストラクタで許可されている操作のサブセットしか実行できないため、それほど強力ではありません (たとえば、ファイナライザは他のオブジェクトを確実に使用できませんが、デストラクタは可能です)、そのサブセット ファイナライザを記述する場合でも、正しく記述することは非常に困難です。また、ファイナライズ可能なオブジェクトの収集にはコストがかかります。各ファイナライズ可能なオブジェクトと、そこから到達可能なオブジェクトの潜在的に巨大なグラフは、次の GC 世代に昇格されます。

これは一般的な JVM にも当てはまり、特に HotSpot にも当てはまりますか?

4

4 に答える 4

4

以下は、2004 年の明確な声明です。

ファイナライザーを持つオブジェクト (重要なfinalize()メソッド) は、ファイナライザーのないオブジェクトと比較してかなりのオーバーヘッドがあるため、慎重に使用する必要があります。ファイナライズ可能なオブジェクトは、割り当てと収集の両方に時間がかかります。割り当て時に、JVM はファイナライズ可能なオブジェクトをガベージ コレクターに登録する必要があり、(少なくとも HotSpot JVM 実装では) ファイナライズ可能なオブジェクトは、他のほとんどのオブジェクトよりも遅い割り当てパスに従う必要があります。同様に、ファイナライズ可能なオブジェクトも収集に時間がかかります。ファイナライズ可能なオブジェクトを回収するには、ガベージ コレクション サイクルが少なくとも 2 回 (最良の場合) かかり、ガベージ コレクターはファイナライザーを呼び出すために余分な作業を行う必要があります。その結果、到達不能なファイナライズ可能オブジェクトによって使用されるメモリがより長く保持されるため、オブジェクトの割り当てと収集に費やされる時間が長くなり、ガベージ コレクターへの負担が大きくなります。

于 2010-06-02T05:14:06.707 に答える
3

以下は、 Effective Java 2nd Editionからの引用の一部です: 項目 7: ファイナライザーを避ける:

ファイナライザは予測不可能で、危険な場合が多く、一般的に不要です。それらを使用すると、動作が不安定になり、パフォーマンスが低下し、移植性の問題が発生する可能性があります。ファイナライザーの有効な用途はほとんどありません。[...]経験則として、ファイナライザーは避けるべきです。

実際、ファイナライザーが必要であることを本当に確認する必要があります。ほとんどの場合、あなたはしません。

C++ プログラマは、ファイナライザを Java の C++ デストラクタの類似物と考えないように注意してください。C++ では、デストラクタはオブジェクトに関連付けられたリソースを再利用する通常の方法であり、コンストラクタに必要な対応物です。Java では、ガベージ コレクターは、到達不能になったオブジェクトに関連付けられたストレージを再利用するため、プログラマー側で特別な作業を行う必要はありません。C++ デストラクタは、他の非メモリ リソースを再利用するためにも使用されます。Java では、try-finally一般にこの目的でブロックが使用されます。

ファイナライザーが呼び出されるときのセマンティクスも考慮することが重要です。

JLS 12.6 クラスインスタンスのファイナライズ

Java プログラミング言語では、finalizerが呼び出されるまでの時間 [...または] 特定のオブジェクトのファイナライザーを呼び出すスレッドを指定しません。[...] ファイナライズ中にキャッチされない例外がスローされた場合、例外は無視され、そのオブジェクトのファイナライズは終了します。(JLS 12.6.2) ファイナライザーの呼び出しが順序付けされていない

さらに、オンデマンドでファイナライザーを実行する唯一のメカニズムが壊れています。以下の引用は、Effective Java 2nd Edition からのものです。

[...] ファイナライズを保証すると主張する唯一の方法はSystem.runFinalizersOnExit、 とその邪悪な双子ですRuntime.runFinalizersOnExit。これらのメソッドには致命的な欠陥があり、推奨されていません。

Bloch は、パフォーマンスのペナルティについてさらにコメントしました (彼を強調してください)。

ああ、もう 1 つあります。ファイナライザーを使用すると、パフォーマンス大幅に低下します。私のマシンでは、単純なオブジェクトの作成と破棄にかかる時間は約 5.6ns です。ファイナライザーを追加すると、時間が 2,400ns に増加します。つまり、ファイナライザーを使用してオブジェクトを作成および破棄すると、約 430 倍遅くなります。

ベンチマークの方法論に関する詳細がほとんどないため、特定の数値はあまり意味がないと思いますが、広く文書化されていることを裏付けています。ファイナライザーは非常にコストがかかります。

この本では、ファイナライザーの使用が有効なまれなシナリオについて説明しています。この回答からの引用の省略は意図的なものです。

于 2010-06-02T07:31:40.187 に答える
1

Javaには、ファイナライザーに対して非常によく似たメカニズムがあります。ファイナライザーに関する優れた記事は次のとおりです。http ://www.javaworld.com/javaworld/jw-06-1998/jw-06-techniques.html

Javaの一般的な経験則は、それらを使用しないことです。

于 2010-06-02T04:31:10.730 に答える