5

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

オンライン、私はこの図は、ガベージコレクションのプロセスを示す発見し、最終決定:

This describes the order of operations involving finalize and the JGC:

質問のカップル:

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

私が興味なぜ私が説明しなければならないと仮定します。私はLWJGLをたくさん使っていますが、Javaオブジェクトを使ってOpenGLリソースを自動的にクリーンアップさせるためにfinalizeを使うことができたら、APIの面で本当に素晴らしいことができるようです。

+2

これはあなたの質問に対する直接的な答えではありませんが、ファイナライズが頻繁に使用されない多くの理由の1つであるファイナンスが呼び出されることは保証されていません。 (編集:それがあってもJava管理メモリのメモリ圧迫のために呼び出されます。つまり、他のリソースを解放するためにそれを使用しようとすると、それらを使い果たしてあなたのプログラムがクラッシュしても、GCがGCを実行して(例えば)ファイルハンドルを再利用することをJavaが知らないからです。 – jacobm

答えて

3

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

リソースをクリーンアップすることは、正確にはfinalizeメソッドのためです。だから、そこには良いはずです。しかし、いくつかの警告:

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

と呼ばれる場合は保証されません。記憶が逼迫すると、これはより早くなります。空きメモリがたくさんある場合は、それが後になります。これは大丈夫かもしれません:たくさんのメモリがあれば、リソースを解放することに心配する人はいないかもしれません。 (彼らにぶら下がっするあなた心配になり、その場合には、同時に実行されている他のソフトウェア、と干渉するかもしれません。)

私ususalソリューションをクリーンアップし処分方法のいくつかの種類を持っていることです。私はできるだけ明示的に呼んでいます。できるだけ早く呼びます。次に、メソッドを呼び出すfinalizeメソッドを追加します(メソッド)。 (が複数回呼び出されたときときうまく動作する必要があります方法を処分することに注意してください!確かに、プログラミングのこの種の以前の呼び出しが成功し、まだ欠けて行われた場合、私はが確認されていない、finalize数回を配置呼ぶかもしれませんできるだけ早く効果的に呼び出されるようになりました。)今、理想的には、私のリソースはもはやそれらが必要なくなり次第解放されます。しかし、私がリソースを持つオブジェクトの追跡を失った場合、メモリが不足しているときに助けが必要なときにfinalizeメソッドが私を救済します。

5

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

私が知っている限り、finalize()メソッドから静的メソッド呼び出しを作成するのに問題はなく、finalize()から新しいメソッドを作成することはできますが、これはプログラミングの貧弱さです。

あなたは決済のためにfinalize()に頼るべきではありません。あなたが行くにつれて解決する方がよいでしょう。 finalize()を使用するのではなく、try、catch、finallyを使用する方が好みです。特に、finalize()を使用すると、呼び出し可能な場合に備えて、ファイナライズ可能なオブジェクトが参照する他のすべてのオブジェクトをJVMに保持させることができます。これは、あなたが使用する必要のないメモリにあなたの持ち株を意味します。さらに重要なことは、これは、JVMが決してオブジェクトを廃棄しないようにすることを意味します。競合状態。

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

リソースを終了した時点でリソースを消去し、finalize()に依存しないようにしてください。これは私のアドバイスです。

1

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

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

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

広告3.ファイナライザから静的メソッドを呼び出すときに問題はありません。

Ad 4.ポイント2で述べたように、ファイナライズ時に別のライブオブジェクトに参照を置くことで、オブジェクトがガベージコレクション(復活)するのを防ぐことができます。しかし、これは微妙な動作であり、おそらく良い習慣ではありません。

要約すると、ファイナライザを使用してリソースをクリーンアップすることはできません。あなたは手動で処理する必要があり、ケースのファイナライザは、せいぜいコードをいくつかの程度まで覆い隠すためのバックアップメカニズムとして使用することをお勧めします。残念ながら、ファイナライザを使用してOpenGLリソースをクリーンアップすることで、APIをより良くする考えはおそらくうまくいかないでしょう。