5

それで、私は最近 Java で finalize メソッドを発見しました (以前に見逃した理由はわかりませんが、あります)。これは、私が取り組んでいる多くの問題に対する答えのように思えますが、最初にもう少し情報を得たいと思っていました.

オンラインで、ガベージ コレクションとファイナライズのプロセスを示す次の図を見つけました。

これは、ファイナライズと JGC を含む操作の順序を示しています。

いくつかの質問:

  1. これは別のスレッドで行われますよね?
  2. ファイナライズ中に新しいオブジェクトをインスタンス化するとどうなりますか? それは許されますか?
  3. finalize から静的メソッドを呼び出すとどうなりますか?
  4. finalize 内からオブジェクトへの新しい参照を確立するとどうなりますか?

興味を持った理由を説明する必要があると思います。私は LWJGL を頻繁に使用していますが、ファイナライズを使用して Java オブジェクトに OpenGL リソースを自動的にクリーンアップさせることができれば、API に関して非常に優れたことができるように思えます。

4

3 に答える 3

5

finalize() は、特定のオブジェクトへの参照が存在しないことが検出されると、Java ガベージ コレクターによって呼び出されます。finalize() は、Object クラスを通じてすべての Java オブジェクトに継承されます。

私の知る限り、finalize() メソッドから静的メソッド呼び出しを作成するのに問題はなく、finalize() から新しい参照を確立することもできますが、これはプログラミングの実践方法としては不十分です。

片付けのために finalize() に頼るべきではありません。私は、finalize() を使用するよりも、try、catch、finally を使用してクリアすることを好みます。特に、finalize() を使用すると、ファイナライズ可能なオブジェクトが参照する他のすべてのオブジェクトを JVM が保持するようになります。これは、使用する必要のないメモリを保持していることを意味します。さらに重要なことは、競合状態などの別のオブジェクトの finalize メソッドが必要になった場合に備えてオブジェクトを保持する必要があるため、JVM がオブジェクトを破棄しないようにすることもできるということです。

また、GC が呼び出されない可能性も十分に考えてください。したがって、 finalize() が呼び出されることを実際に保証することはできません。

私のアドバイスは、リソースを使い終わったら片付けて、finalize() に頼らないことです。

于 2012-03-04T17:02:27.570 に答える
3

どのスレッドが使用されるかについての保証はないと思います。新しいオブジェクトがインスタンス化され、静的メソッドが呼び出されることがあります。オブジェクトへの新しい参照を確立すると、ガベージ コレクションが行われなくなりますが、メソッドfinalizeが再度呼び出されることはありません。これは望ましくありません。

リソースをクリーンアップすることはまさにこのfinalize方法の目的であるため、適切に行う必要があります。ただし、いくつかの警告があります。

メソッドが呼び出される保証はありません。 プログラムが停止したときに自動的に解放されないリソースを拘束している場合は、に依存しないでくださいfinalize

メソッドがいつ呼び出されるかは保証されません。メモリがタイトなため、これはより早くなります。空きメモリがたくさんあるので、仮にあったとしても遅くなります。これはあなたに合っているかもしれません: メモリがたくさんあるので、リソースを解放することについてそれほど心配する必要はないかもしれません。(ただし、それらに固執すると、同時に実行されている他のソフトウェアに干渉する可能性があります。その場合心配です。)

私の通常の解決策は、クリーンアップを行うある種の破棄メソッドを用意することです。可能であれば、ある時点で明示的に呼び出し、できるだけ早く呼び出します。次に、 disposeメソッドを呼び出すだけの finalize メソッドを追加します。( disposeメソッドは、複数回呼び出されたときに適切に動作する必要があることに注意してください! 実際、この種のプログラミングでは、以前の呼び出しが正常に行われたかどうかを確認せずに、すぐに効果的に呼び出されるようにしたい場合に、disposeを外部で複数回呼び出す可能性があります。finalize理想的には、私のリソースは、不要になったらすぐに解放されます。ただし、リソースを含むオブジェクトを見失うと、finalizeメソッドは、メモリが不足し、助けが必要なときに私を救済します.

于 2012-03-04T17:51:58.900 に答える
1

まず第一に、すべてのオブジェクトに対してファイナライズがまったく実行されるという保証はないことを覚えておいてください。これを使用して、オブジェクトに関連付けられたネイティブ コードで割り当てられたメモリを解放できますが、純粋な Java コードのほとんどの使用例は、リソースをクリーンアップする「バックアップ」メカニズムを実行することだけです。これは、ほとんどの場合、手動でリソースを解放する必要があることを意味します。ファイナライザーは、標準的な方法でクリーンアップを行うのを忘れた場合、一種のヘルパーとしてのみ機能する可能性があります。ただし、それらをクリーンアップの唯一のメカニズムまたは主要なメカニズムとして使用することはできません。さらに一般的に言えば、実行中のファイナライザーに依存するコードの正確性を記述するべきではありません。

広告 1. 私が知る限り、どのスレッドが を呼び出すかについての保証はありませんがfinalize()、実際にはこれはおそらく GC スレッドの 1 つになるでしょう。

広告 2. 新しいオブジェクトのインスタンス化が許可されます。ただし、ファイナライザーでのオブジェクト参照の処理には多くの落とし穴があります。特に、何らかのライブ オブジェクトでファイナライズされているオブジェクトへのハード参照を保存すると、ガベージ コレクションが行われる直前のオブジェクトがクリーンアップされるのを防ぐことができます。この種のオブジェクトの復活は、制御不能になった場合にリソースを枯渇させる可能性があります。また、 の例外にも注意してfinalize()ください。ファイナライズが停止する可能性がありますが、プログラムがそれらについて自動的に学習する方法はありません。コードを try-catch ブロックでラップし、自分で情報を伝達する必要があります。また、ファイナライザの実行時間が長いと、オブジェクトのキューが構築され、大量のメモリが消費される可能性があります。その他の注目すべき問題と制限については、このJavaWorldの記事

広告 3. ファイナライザーからの静的メソッドの呼び出しに問題はないはずです。

広告 4. ポイント 2 で述べたように、ファイナライズ中にオブジェクトへの参照を別のライブ オブジェクトに配置することで、オブジェクトがガベージ コレクションされる (復活する) のを防ぐことができます。ただし、これはトリッキーな動作であり、おそらく適切な方法ではありません。

要約すると、リソースのクリーンアップをファイナライザーに頼ることはできません。それを手動で処理する必要があり、あなたの場合のファイナライザーは、せいぜい、ずさんなコーディングをある程度隠蔽するためのバックアップメカニズムとして使用される可能性があります。これは、残念ながら、ファイナライザーを使用して OpenGL リソースをクリーンアップすることで API をより良くするというあなたの考えはおそらくうまくいかないことを意味します。

于 2012-03-04T17:23:18.080 に答える