27

(この質問はWhy would you ever implement finalize()? とは異なります。この質問は Java プラットフォームからの非推奨に関するもので、もう 1 つの質問はアプリケーションでこのメカニズムを使用する必要があるかどうかに関するものです。)

finalize()メソッドが Java 9 で非推奨になったのはなぜですか?

はい、間違った方法で使用される可能性があります (ガベージ コレクションからオブジェクトを保存する [1 回だけ] またはその中のネイティブ リソースを閉じようとする [まったく閉じないよりはましです]) など、他の多くの方法があります。間違って使用される可能性があります。

ではfinalize()、Java から追い出す必要があるほど危険またはまったく役に立たないのでしょうか?

4

1 に答える 1

34

質問はObject.finalizeメソッドについて尋ねていましたが、主題は実際にはファイナライズメカニズム全体に関するものです。このメカニズムには、サーフェス API だけでなく、Object.finalizeオブジェクトのライフサイクルに関するプログラミング言語の仕様や、JVM でのガベージ コレクターの実装への実際的な影響も含まれます。

アプリケーションの観点からファイナライズを使用するのが難しい理由については、多くのことが書かれています。なぜ finalize() を実装するのですか?の質問を参照してください。ファイナライズよりも Java 9 Cleaner を優先する必要がありますか? とその答え。Joshua Bloch による「 Effective Java」の第 3 版、項目 8も参照してください。

簡単に言うと、ファイナライザーの使用に関連する問題に関するいくつかのポイントは次のとおりです。

  • それらは正しくプログラムするのが難しいことで有名です

  • 特に、オブジェクトが予期せず (ただし正しく) 到達不能になると、予期せず実行される可能性があります。たとえば、この質問に対する私の回答を参照してください

  • ファイナライズは、サブクラス/スーパークラスの関係を簡単に壊す可能性があります

  • ファイナライザ間に順序付けはありません

  • 特定のオブジェクトのfinalizeメソッドは、そのオブジェクトが「復活」した場合でも、JVM によって最大 1 回呼び出されます。

  • ファイナライズの適時性について、またはそれがまったく実行されるという保証さえありません

  • 明示的な登録または登録解除のメカニズムはありません

上記は、ファイナライズの使用に関する問題です。上記の問題のリストを考えると、ファイナライズの使用を検討している人は誰でも再考する必要があります。しかし、これらの問題は、Java プラットフォームでのファイナライズを非推奨にするのに十分でしょうか? 以下のセクションで説明するいくつかの追加の理由があります。

ファイナライズによってシステムが脆弱になる可能性がある

ファイナライズを正しく使用するオブジェクトを作成したとしても、オブジェクトが大規模なシステムに統合されたときに問題が発生する可能性があります。ファイナライズをまったく使用しない場合でも、一部でファイナライズを使用する大規模なシステムに統合されると、問題が発生する可能性があります。一般的な問題は、ガベージを作成するワーカー スレッドがガベージ コレクターとバランスを取る必要があることです。ガベージ コレクターが遅れをとった場合、少なくとも一部のコレクターは「世界を停止」し、完全なコレクションを実行して追いつくことができます。ファイナライズは、この相互作用を複雑にします。ガベージ コレクターがアプリケーション スレッドに対応している場合でも、ファイナライズによってボトルネックが発生し、システムの速度が低下したり、リソースの解放が遅れてリソースが枯渇したりする可能性があります。これはシステムです問題。ファイナライズを使用する実際のコードが正しい場合でも、正しくプログラムされたシステムで問題が発生する可能性があります。

(編集 2021-09-16:この質問は、システムが低負荷では正常に動作するが、高負荷では失敗する問題について説明しています。おそらく、割り当ての相対速度が高負荷でのファイナライズの速度を上回っているためです。)

ファイナライズはセキュリティの問題に貢献します

SEI CERT Oracle Coding Standard for Javaには、ルールMET12-J: Do not use finalizers があります。(注、これはセキュアコーディングに関するサイトです。)特に、

ファイナライザーを不適切に使用すると、ガベージ コレクションの準備が整ったオブジェクトが復活し、サービス拒否の脆弱性が発生する可能性があります。

Oracle のJava SE のセキュア コーディング ガイドラインは、ファイナライズを使用して発生する可能性がある潜在的なセキュリティの問題についてより明確に示しています。この場合、ファイナライズを使用するコードでは問題ありません。代わりに、攻撃者はファイナライズを使用して、適切に防御していない機密コードを攻撃することができます。特に、ガイドライン 7-3 / OBJECT-3は、一部で次のように述べています。

非最終クラスの部分的に初期化されたインスタンスは、ファイナライザー攻撃を介してアクセスできます。攻撃者は、サブクラスの保護されfinalizeたメソッドをオーバーライドし、そのサブクラスの新しいインスタンスを作成しようとします。この試みは失敗しますが、攻撃者は単に例外を無視し、仮想マシンが部分的に初期化されたオブジェクトに対してファイナライズを実行するのを待ちます。それが発生すると、悪意のあるメソッドの実装が呼び出され、攻撃者はファイナライズされるオブジェクトへの参照にfinalizeアクセスできます。thisオブジェクトは部分的にしか初期化されていませんが、攻撃者は引き続きメソッドを呼び出すことができます....

したがって、プラットフォームにファイナライズ メカニズムが存在することは、高保証のコードを記述しようとしているプログラマーに負担を課します。

ファイナライズにより仕様が複雑になる

Java プラットフォームは、言語、仮想マシン、クラス ライブラリ API の仕様など、いくつかの仕様によって定義されています。ファイナライズのインパクトはそれらすべてに薄く広がっているが、繰り返しその存在感を感じさせる。たとえば、ファイナライズはオブジェクトの作成と非常に微妙な相互作用をします (これはすでに十分に複雑です)。ファイナライズは Java の公開 API にも現れています。つまり、これらの API の進化は (現在まで) 以前に指定された動作との互換性を維持する必要がありました。これらの仕様を進化させることは、ファイナライズの存在によりコストがかかります。

ファイナライズにより実装が複雑になる

これは主にガベージコレクターに関するものです。いくつかのガベージ コレクションの実装があり、すべてファイナライズの実装コストを支払う必要があります。ファイナライズが使用されていない場合、実装は実行時のオーバーヘッドを最小限に抑えるのに非常に優れています。ただし、実装はまだそこにある必要があり、正しく、十分にテストする必要があります。これは、進行中の開発と保守の負担です。

概要

プログラマーがファイナライズを使用することは推奨されていないことを、他の場所で見てきました。ただし、何かが役に立たない場合、必ずしもそれを非推奨にする必要があるとは限りません。上記の点は、ファイナライズを使用しなくても、プラットフォームにメカニズムが存在するだけで、継続的な仕様、開発、および保守コストが課せられるという事実を示しています。メカニズムの有用性の欠如とそれが課すコストを考えると、それを廃止することは理にかなっています。最終的に、ファイナライズを取り除くことは、すべての人に利益をもたらします。

この記事の執筆時点 (2019-06-04) では、Java からファイナライズを削除する具体的な計画はありません。しかし、それは確かにそうする意図です。このメソッドは廃止されましたObject.finalizeが、削除対象としてマークされていません。これは、プログラマーがこのメカニズムの使用をやめることを正式に推奨するものです。ファイナライズを使用すべきではないことは非公式に知られていますが、もちろん正式な手順を実行する必要があります。さらに、finalizeライブラリ クラスの特定のメソッド (たとえば、ZipFile.finalize) は「削除のために」廃止されました。つまり、これらのクラスのファイナライズ動作は、将来のリリースから削除される可能性があります。最終的には、JVM でのファイナライズを無効にしたいと考えています (おそらく最初はオプションで、その後はデフォルトで)。

(編集 2021-11-03: JEP 421が投稿されたばかりで、削除のためにファイナライズを非推奨にすることを提案しています。この記事の執筆時点では「候補」の状態ですが、前進することを期待しています。この JEP によって追加された非推奨は正式なものです。ファイナライズは、後続のJavaリリースのある時点で削除されるという通知おそらく驚くべきことではないが、この回答とJEPの内容にはかなりの重複がありますが、JEPはより正確であり、トピック。)

于 2019-06-05T04:41:07.087 に答える