ファイナライズの危険性

ファントムリンクの使用に関する記事を書いている間、finalizeメソッドを使用するときに発生する不便さに言及する必要がありました。 さらに、このトピックはすべての初心者のJava開発者にとって有用であり、経験豊富なプログラマーの中には、ファイナライズメソッドの使用が非常に簡単であるため、いくつかの点を思い出すのを忘れないだろうと信じています。 ファイナライズメソッドを使用しないと固く信じていても、これは前の同僚がそれらを使用しなかったことを意味するものではなく、それらがどのように機能するかを理解する必要はありません。



それでは、明白なものから直感的でないものに移りましょう。

  1. finalizeメソッドは、オブジェクトが到達不能になった直後の最初のガベージコレクション中に呼び出されるため、アプリケーションがこのガベージコレクションに到達せずに作業を完了することができるため、まったく呼び出されない可能性があります。 もちろん、 System.runFinalizersOnExit(true)というすばらしいメソッドが1つありますが、これはプログラムの開始時に呼び出されますが、ファイナライズメソッドは、適切なアプリケーションの停止中に既に到達できないオブジェクトに対して機能します。
  2. JVM仕様は、ファイナライズ方法のマルチスレッド化の問題に対処していません。 HotSpotでは、すべてのfinalizeメソッドが単一のFinalizerスレッドで順番に呼び出されます。 ただし、 System.runFinalization()メソッドを呼び出すと、 現在のスレッドをブロックし、キューに適切なオブジェクトがある場合にfinalizeメソッドを実行する別のスレッドが生成されます。 さらに、これはファイナライザーのメインストリームと並行して発生する可能性があります。
  3. finalizeメソッドをオーバーライドすると、2番目のガベージコレクションまでメモリから削除されないため、死後のオブジェクトの寿命が大幅に長くなります。 そして、最初の2つの点を考えると、finalizeメソッドがあなたにとって難しい場合、および/またはそのようなオブジェクトがたくさんある場合、オブジェクトはファイナライズフェーズで長時間ハングし、メモリスペースを占有し続ける可能性があります。
  4. finalizeメソッドの実行中に、オブジェクトへの参照を復元できます。たとえば、静的なコンテキストに配置することにより、オブジェクトを復活させます。 このような操作の危険性は、2回目にこのオブジェクトのfinalizeメソッドが呼び出されないことです。 したがって、何らかの理由でこのオブジェクトを本当に復活させる必要がある場合は、finalizeメソッド内にコピーを作成することをお勧めします。
  5. finalizeメソッドを使用する際の最も厄介な問題の1つは、再レンダリングです。 オーバーライドされたfinalizeメソッドを持つ2つのオブジェクトがあり、一方が他方を参照しているとします。 したがって、これらのオブジェクトが到達不能になった場合、ファイナライズメソッドを呼び出す順序はランダムな順序で発生します。 したがって、別のオブジェクトのfinalizeメソッドから既にファイナライズされたオブジェクトのメソッドを呼び出すと、エラーが発生する可能性があります。 さらに、問題はすべてのオブジェクトで発生するわけではなく、デバッグ時に頭痛の種になります。
  6. 有名な著書「Effective Java:Programming Language Guide」の著者であるJoshua Blochによると、オーバーライドされたfinalizeメソッドを持つオブジェクトの場合、割り当てとアセンブリは通常のオブジェクトよりも430倍遅くなります。
  7. メソッド本体でスローされた例外はすべて無視されます。
  8. メソッドの最後でsuper.finalize()を呼び出すことを忘れてはなりません。 そして、前の段落を考えると、finallyブロックでこれを行う必要があります。


上記に従って、finalizeメソッドの使用は可能な限り回避する必要があります。むしろ、それに頼らないでください。 プログラムでリソースを解放し、何らかの理由でこれが行われなかった場合に問題を見つけて修正するために、finalizeメソッドでログを記録することをお勧めします。

オブジェクトを組み立てるときにまだリソースを解放する必要がある場合は、このためにファントムリンク使用することをお勧めします



All Articles