回答:
Joshua BlochのEffective Java(第2版)によると、finalize()
役に立つシナリオは2つあります。
1つは、オブジェクトの所有者が明示的な終了メソッドの呼び出しを忘れた場合の「セーフティネット」として機能することです。ファイナライザがすぐに呼び出されるという保証はありませんが、クライアントが明示的な終了メソッドの呼び出しに失敗した場合(まれに)に、リソースを決して解放しないほうがよい場合があります。ただし、ファイナライザは、リソースが終了していないことを検出した場合、警告を記録する必要があります
ファイナライザの2番目の合法的な使用法は、ネイティブピアを持つオブジェクトに関するものです。ネイティブピアは、通常のオブジェクトがネイティブメソッドを介して委任するネイティブオブジェクトです。ネイティブピアは通常のオブジェクトではないため、ガベージコレクターはそのことを認識せず、Javaピアが回収されるときに回収することはできません。ファイナライザーは、ネイティブピアが重要なリソースを保持していないことを前提として、このタスクを実行するための適切な手段です。ネイティブピアが、すぐに終了する必要のあるリソースを保持している場合、上記のように、クラスには明示的な終了メソッドが必要です。終了メソッドは、重要なリソースを解放するために必要なことをすべて実行する必要があります。
詳細については、27ページの項目7を参照してください。
ファイナライザは、ネイティブリソースの管理に重要です。たとえば、オブジェクトは、非Java APIを使用してオペレーティングシステムからWidgetHandleを割り当てる必要がある場合があります。オブジェクトがGCされたときにそのWidgetHandleをリリースしないと、WidgetHandlesがリークすることになります。
重要なのは、「ファイナライザーが呼び出されない」ケースが、単に単純に故障することです。
これらの3つのケースすべてで、ネイティブリークがないか(プログラムが実行されていないため)、または非ネイティブリークが既にあります(管理オブジェクトを割り当てずに管理オブジェクトを割り当て続ける場合) GC'd)。
「呼び出されるファイナライザに依存しない」という警告は、実際にはプログラムロジックにファイナライザを使用しないことに関するものです。たとえば、構築中にファイルのカウンターをインクリメントし、ファイナライザーでデクリメントすることで、プログラムのすべてのインスタンスに存在するオブジェクトの数を追跡したくない場合があります-オブジェクトが保証されるわけではないためですファイナライズされると、このファイルカウンタはおそらく0には戻らないでしょう。これは、プログラムが正常に終了する(電源障害など)ことに依存すべきではない、より一般的な原則の特別なケースです。
ただし、ネイティブリソースの管理では、ファイナライザが実行されない場合は、実行されなくても構わない場合に対応します。
close()
到達不能になる前に呼び出されない場合)にファイナライザーがフォールバックであると言う方が正しいでしょう
このメソッドの目的は、APIドキュメントで次のように説明されています。
Java仮想マシンが、他のオブジェクトのファイナライズによって実行されたアクションの結果を除いて、まだ終了していないスレッドがこのオブジェクトにアクセスできる手段がなくなったと判断した場合に呼び出されます。または完成する準備ができているクラス...
finalize
... の通常の目的は、オブジェクトが取り消せなく破棄される前にクリーンアップアクションを実行することです。たとえば、入出力接続を表すオブジェクトのfinalizeメソッドは、オブジェクトが永久に破棄される前に明示的なI / Oトランザクションを実行して接続を切断する場合があります...
言語デザイナーが、アプリケーションプログラマーの制御を超えた方法(「絶対に頼るべきではない」)で「オブジェクトを取り消せないように破棄する」(ガベージコレクション)を選択した理由にさらに興味がある場合は、関連する回答で説明されています質問:
自動ガベージコレクション...は、CおよびC ++プログラマを悩ますプログラミングエラーのクラス全体を排除します。システムが多くのエラーを迅速に検出し、本番コードが出荷されるまで主要な問題が休止状態にならないことを確信して、Javaコードを開発できます。
上記の引用は、Java設計目標に関する公式文書から引用されたものです。つまり、Java言語設計者がこのように決定した理由を説明する信頼できる参照と見なすことができます。
この設定のより詳細で言語にとらわれない議論については、OOSCセクション9.6自動メモリ管理を参照してください(実際、このようなセクションだけでなく、そのようなものに興味があるなら、第9章全体を読む価値があります)。このセクションは、明確なステートメントで開きます。
優れたオブジェクト指向環境は、到達不能なオブジェクトを検出して再生する自動メモリ管理メカニズムを提供する必要があり、アプリケーション開発者は自分の仕事であるアプリケーション開発に専念できます。
このような機能を使用可能にすることがいかに重要かを示すには、前述の説明で十分です。Michael SchweitzerとLambert Stretherの言葉:
自動メモリ管理のないオブジェクト指向プログラムは、安全弁のない圧力鍋とほぼ同じです。遅かれ早かれ、確実に爆発するでしょう!
警告:私は時代遅れかもしれませんが、これは数年前の私の理解です:
一般に、ファイナライザの実行の保証はありません-または、まったく実行されるという保証さえありませんが、一部のJVMでは、プログラムが終了する前に完全なGCおよびファイナライズを要求できます(もちろん、プログラムに時間がかかります終了します。これはデフォルトの動作モードではありません)。
また、一部のGCは、これによりベンチマークでのパフォーマンスが向上することを期待して、ファイナライザを持つGCオブジェクトを明示的に遅延または回避することが知られていました。
残念ながら、これらの動作は、ファイナライザが推奨された元の理由と矛盾するため、代わりに明示的に呼び出されるシャットダウンメソッドの使用を推奨しています。
破棄する前に実際にクリーンアップする必要があるオブジェクトがあり、ユーザーが本当にそうすることを信頼できない場合は、ファイナライザーを検討する価値があります。しかし一般に、初期の例のいくつかで見たように、現代のJavaコードではそれほど頻繁に見ないという理由があります。
GoogleのJavaのスタイルガイドは、件名にいくつかの賢明なアドバイスがあります:
オーバーライドすることは非常にまれ
Object.finalize
です。ヒント:しないでください。どうしても必要な場合は、最初に「有効なJava項目7」「ファイナライザーを回避する」をよく読んで理解し、それを実行しないでください。
PhantomReference
、ReferenceQueue
代わりにビルドしたいでしょう。
PhantomReference
、より良いソリューションだと思います。ファイナライザは、Javaの初期の時代から残されたいぼであり、同様のObject.clone()
タイプや生のタイプは、最も忘れられている言語の一部です。
Java言語仕様(Java SEの7)は述べています:
ファイナライザは、自動ストレージマネージャによって自動的に解放できないリソースを解放する機会を提供します。そのような状況では、オブジェクトが使用するメモリを単に再生するだけでは、そのオブジェクトが保持しているリソースが再生されることを保証しません。