【Java】GCとfinalizeメソッドの関係
ガベージ・コレクションとfinalizerメソッドの関係について、ちょこっと調べたので簡単にメモしておく。
1.finalizeメソッドとFinalizer
Finalizer・・・オブジェクトのfinalizeメソッドを呼び出すためのスレッド。
2.finalizeメソッドの有無によるGCの挙動の違い
2-1.finalizeメソッドがない時
引用:@IT
finalizeメソッドがない場合、オブジェクトはルートセットから参照されなくなった時点でGC対象となり、
次のGC実行時に破棄される。
2-2.finalizeメソッドがある時
引用:@IT
finlaizeメソッドがある場合、オブジェクトはルートセットから参照されなくなった時点でGC対象となり、
次のGC実行時に、GCによってfinalize対象リストへと登録される。
そして、Finalizerスレッドがfinalizeメソッドを実行した時点で、再度GC対象となり、
次のGC実行時に、今度こそ本当に破棄される。
つまり、finalizeが定義されているオブジェクトが破棄されるまでには、少なくとも2回以上のGCが走る必要がある。
また、当然ながらfinalizeが定義されているオブジェクトだけでなく、
そのインスタンスが参照するオブジェクトもまた初回のGCでは解放されない。
さらに、finalizeメソッドが実行される順番は不定であり、
期待通りのタイミングでfinalizeメソッドが呼ばれるとは限らない。
特にオブジェクトを大量に生成した場合には、Finalizerスレッドが処理に追いつかず、
2回目のGC時にもまだFinalizerからの参照が残っているために、オブジェクトが破棄されない可能性がある。
3.finalizeメソッドは実行されないことがある
上記2-2.で記載した通り、finalizeメソッドはGCによりfinalize対象リストに
登録されたオブジェクトに対して行われるものなので、
GCが実行されない限りfinalizeは呼ばれない。
そして、アプリケーション(javaコマンド)が終了する際にはGCは呼ばれない(?)ことがあるようなので、
finalizeメソッドは実行されないままアプリケーションが終了することがある。
以上のことから、finalizeを実装したクラスを作成することには、
・意図したタイミングで破棄されないことによるOutOfMemoryのリスク
・finalizeが走らないことによるメモリリークの可能性
等のリスクがあるため、可能な限りfinalizeメソッドは実装しない方が良いと思われる。
<参考>
JavaのGC頻度に惑わされた年末年始の苦いメモリ (3/3) - @IT
3.10.5 java.lang.Object.finalize()についての注意事項
Objectクラス finalizeメソッド