web-dev-qa-db-ja.com

finalizeメソッドがJavaに含まれているのはなぜですか?

この投稿 によると、finalizeメソッドの呼び出しに依存するべきではありません。では、なぜJavaをプログラミング言語に組み込んだのでしょうか?

mightが呼び出される関数をプログラミング言語に含めるのはひどい決定のようです。

44
patstuart

Joshua Blochの効果的なJava(第2版))によると、finalize()が役立つシナリオは2つあります。

  1. 1つは、オブジェクトの所有者が明示的な終了メソッドの呼び出しを忘れた場合の「セーフティネット」として機能することです。ファイナライザがすぐに呼び出される保証はありませんが、クライアントが明示的な終了メソッドを呼び出せない場合(できればまれ)に、リソースを解放するのは遅くない方がよい場合があります。しかし、ファイナライザは、リソースが終了していないことを発見した場合、警告をログに記録する必要があります

  2. ファイナライザの2番目の正当な使用は、ネイティブピアを持つオブジェクトに関係します。ネイティブピアは、通常のオブジェクトがネイティブメソッドを介して委任するネイティブオブジェクトです。ネイティブピアは通常のオブジェクトではないため、ガベージコレクターはそれを認識せず、Javaピアが再利用されるときに再利用できません。ファイナライザはこれを実行するための適切な手段ですタスク。ネイティブピアが重要なリソースを保持していないと仮定します。ネイティブピアがすぐに終了する必要があるリソースを保持している場合、クラスには、上記のように明示的な終了メソッドが必要です。終了メソッドは、重要なリソースを解放するために必要なことをすべて実行する必要があります。

詳細については、27ページの項目7を参照してください。

41
bbalchev

ファイナライザは、ネイティブリソースの管理にとって重要です。たとえば、オブジェクトが非Java APIを使用してオペレーティングシステムからWidgetHandleを割り当てる必要がある場合があります。オブジェクトがGCされたときにそのWidgetHandleを解放しないと、WidgetHandlesがリークすることになります。

重要なのは、「ファイナライザが呼び出されない」ケースが簡単に壊れることです。

  1. プログラムがすぐにシャットダウンする
  2. プログラムの存続期間中、オブジェクトは「永久に存続する」
  3. コンピュータの電源が切れる/プロセスがOSによって停止される/など

これら3つのケースすべてで、ネイティブリークがない(プログラムが実行されなくなったため)、またはすでにネイティブでないリーク(GCされずに管理オブジェクトを割り当て続ける場合)。

「ファイナライザの呼び出しに依存しないでください」という警告は、実際にはプログラムロジックにファイナライザを使用しないことに関するものです。たとえば、作成中にファイルのカウンターをインクリメントし、ファイナライザーでそれをデクリメントして、プログラムのすべてのインスタンスに存在するオブジェクトの数を追跡したくない場合は、オブジェクトが最終的には、このファイルカウンターはおそらく0に戻りません。これは、プログラムが正常に終了することに依存してはならない、より一般的な原則(電源障害など)の特別なケースです。

ただし、ネイティブリソースの管理では、ファイナライザーが実行されない場合は、実行されなくてもかまわない場合に対応します。

55
Ryan Cavanaugh

このメソッドの目的は、次のように APIドキュメント で説明されています。

Java仮想マシンが、このオブジェクトにまだアクセスできない手段がないと判断した場合に呼び出されます。ファイナライズの準備ができている他のオブジェクトまたはクラスのファイナライズ...

finalize...の通常の目的は、オブジェクトが取り返しのつかない形で破棄される前にクリーンアップアクションを実行することです。たとえば、入出力接続を表すオブジェクトのfinalizeメソッドは、明示的なI/Oトランザクションを実行して、オブジェクトが完全に破棄される前に接続を切断する場合があります...


言語デザイナーが「オブジェクトは取り返しのつかない形で破棄される」(ガベージコレクション)を選択した理由にさらに興味がある場合は、アプリケーションプログラマーを超える方法コントロール(「私たちは決して信頼してはならない」)、これは 関連する質問への回答 で説明されています:

自動ガベージコレクション... CおよびC++プログラマーを悩ますプログラミングエラーのクラス全体を排除します。 Javaコードを開発すると、システムが多くのエラーをすばやく検出し、製品コードが出荷されるまで主要な問題が休眠状態になることはありません。

次に、上記の引用は Java設計目標に関する公式ドキュメント から引用されたものです。つまり、Java言語設計者がこれを決定した理由を説明する信頼できるリファレンスと見なすことができます。仕方。

この設定の言語に依存しない詳細な説明については、 [〜#〜] oosc [〜#〜] セクションを参照してください9.6自動メモリ管理(実際には、このセクションだけでなく、そのようなものに興味がある場合は、第9章全体を読む価値があります。このセクションは明確なステートメントで始まります:

優れたO-O環境は、到達不可能なオブジェクトを検出して再利用する自動メモリ管理メカニズムを提供し、アプリケーション開発者が自分の仕事(アプリケーション開発)に集中できるようにする必要があります。

前述の説明は、そのような機能を利用可能にすることがいかに重要であるかを示すのに十分なはずです。 Michael SchweitzerとLambert Stretherの言葉で:

自動メモリ管理のないオブジェクト指向プログラムは、安全弁のない圧力鍋とほぼ同じです。遅かれ早かれ、確実に爆発します!

5
gnat

ファイナライザが存在するのは、物事を確実にクリーンアップするための効果的な手段であると期待されていたため(実際にはそうではない場合)、およびファイナライザが発明されたとき、クリーンアップを確実にするためのより優れた手段(ファントムリファレンスやtry-withなど)があるためです。 -resources)はまだ存在していませんでした。振り返ってみると、Javaは、「ファイナライズ」機能の実装に費やされた労力が他のクリーンアップ手段に費やされていればより良いと思われますが、その間はほとんど明確ではありませんでしたJavaは当初開発されていました。

4
supercat

警告:私は時代遅れかもしれませんが、これは数年前の私の理解です:

一般に、ファイナライザがいつ実行されるか、または実行されるかどうかの保証はありませんが、一部のJVMでは、プログラムが終了する前に完全なGCとファイナライズを要求できます(もちろん、プログラムに時間がかかることを意味します)終了します。これはデフォルトの操作モードではありません)。

また、一部のGCは、ファイナライザーを備えたオブジェクトのGCを明示的に遅延または回避することで知られています。これにより、ベンチマークのパフォーマンスが向上することを期待しています。

残念ながら、これらの動作はファイナライザが推奨された元の理由と矛盾し、代わりに明示的に呼び出されるシャットダウンメソッドの使用を奨励しています。

破棄する前に本当にクリーンアップする必要があるオブジェクトがあり、ユーザーがそうすることを本当に信頼できない場合でも、ファイナライザは検討する価値があります。しかし、一般的に、最近のいくつかの例で行ったように、最近のJavaコードではそれほど頻繁にそれらを表示しない理由があります。

3
keshlam

Google Java Style Guide には、このテーマに関する賢明なアドバイスがあります:

Object.finalizeをオーバーライドすることは非常にまれです

ヒント:しないでください。どうしても必要な場合は、まずEffective Java項目7、「ファイナライザを避ける」をよく読んで理解し、を理解してください。 しないでください。

1
Daniel Pryden

Java言語仕様(Java SE 7) の状態:

ファイナライザは、自動ストレージマネージャによって自動的に解放できないリソースを解放する機会を提供します。このような状況では、オブジェクトが使用するメモリを再利用するだけでは、オブジェクトが保持していたリソースが再利用されることは保証されません。

1
Benni