Javaでは、finalizeは次のように動作すると仮定しています。ゴミ収集機がメモリーを回収し、オブジェクトが占有しているメモリーを解放する準備ができたら、まずそのオブジェクトのfinalizeメソッドを呼び出し、次にそのオブジェクトをゴミとして回収する必要があるときだけ、実際にオブジェクトを回収します!
finalizeメソッドの役割:日々の開発でfinalizeメソッドを呼び出す必要はありませんし、推奨もされません。JVMが管理するメモリはGCに任されています。finalizeの目的は、主にいくつかの特別なメモリのために使用されます:特別なメモリのアプリケーションでのJNIコールの使用など。finalizeは、すべてのオブジェクトのメモリが解放された後にGCが発生することを確認するために、次のGCが発生したときに、特別なメモリのアプリケーションでJNIコールを再要求する呼び出しの前にGCで使用されます。
ゴミの収集
- Javaのゴミコレクターは、newによって作成されたメモリブロックのみを解放し、newによって作成されなかった「特別なメモリ」は管理しません。
- いわゆる特殊メモリとは、JNIを介してC/C++でシステムから要求されるメモリのことで、手動でクリアしなければメモリに占有されたままになります。
- また、ゴミの収集にはそれ自身のオーバーヘッドがあるので、VMはあまり頻繁にGCしませんし、JVMはメモリがなくなりそうになったときだけGCをトリガーします。
finalize()
- 以上から、Javaのオブジェクトは必ずしもすべてゴミになるわけではなく、オブジェクトが不要になった場合、手動でそれらの「特別なメモリ」を処理する必要がありますが、Javaにはデストラクタがないため、finalize()メソッドを提供してクリーンアップ作業を行うことができます。
- システムがGCを実行する場合、まずfinalizeメソッドを呼び出し、次にオブジェクトのメモリーを回収します。ネイティブで要求されたメモリをGCが再利用する方法はないため、finalizeはゴミ収集の前に重要なクリーンアップを行うために使用されます。
- そのため、finalizeは一般的にJNIが使用されるシナリオで使用され、特別なメモリを解放するためにfinalizeでネイティブメソッドを呼び出す必要があります!
- GCが起こらなければ、finalizeも起こりません。finalizeはObjectのプロテクト・メソッドで、クラス・ファミリーの外からはアクセスできません。
デストラクタの比較対照
- まず第一に、これはデストラクタではありません。JavaにはGCメカニズムがあるため、デストラクタという概念がありません!
- デストラクタは間違いなくオブジェクトを破壊しますが、finalizeはgcメカニズムが頻繁に起こるわけではないので、不確定に実行されます。
その他
- System.gc()を呼び出すと、finalizeメソッドを起動するためにgcが強制的に起こります!しかし、GCはゴミのようなオブジェクトだけをGCし、ゴミでないオブジェクトにはfinalizeは呼ばれません。プログラムの終了とGCは同じ概念ではありません。
- 通常、finalize()はすべて直接呼び出しますが、super.finalize()は親クラスを使うだけです。
- finalizeは通常使われません!実行されるかどうかの不確実性が大きすぎるからです。finalizeを使用してオブジェクトを取り戻すことを期待しないでください。finalizeは、システムがGCを行うときに特別なメモリをクリーンアップするだけで、あなたのコントロールの範囲外です!