Finalizeの仕組み

id:nminoruさんのコメント(http://d.hatena.ne.jp/taedium/20041215のコメント)のおかげでFinalizeの仕組みが見えてきました。どうもありがとうございます。

nminoruさんの解説を参考にjava.lang.ref.Finalizerのコードを読むとなるほどという感じです。(前ちょっと読んだときはさっぱりわかりませんでした。)。ちょっと整理のためにnminoruさんがコメントで書いてくださった内容を自分の言葉でまとめてみます。

  • finalizeをオーバーライドしているクラスのインスタンスhogeが生成されるとJavaVMはFinalizerインスタンスを生成し、hogeのreferentとReferenceQueueが関連づけられる。このQueueをFinalizerThreadが監視する。(状態はunfinalized)
  • hogeがfinarizer-reachableとなるとhogeのreferentがQueueに入れられる。(状態はfinalizableとなる)
  • FinalizerThreadがhogeのreferentを取り出す。
  • hogeのreferentからhoge自身が取り出され、hogeのfinalizeメソッドが実行される。(状態はfinalizedとなる)
  • hogeはガーベージされる。


これでJLSの12.6の状態遷移の図がだんだんわかってきました。ちょっと具体的にあるオブジェクトhogeが図の「A → B → G → M → C → K → F → I」の順番で状態遷移していく例を考えてみました。()のなかはhogeオブジェクトの状態です。

  • A: オブジェクトhogeが生成され、hogeは別のオブジェクトであるreachableなfooにのみ参照される。(reachable & unfinalized)
  • B: fooがfinalizer-reachableとなりさらにfinalizableとなる。(finalizer-reachable & unfinalized)
  • G: hoge自身がfinalizableになる。(finalizer-reachable & finalizable)
  • M: fooのfinalizeメソッドがJavaVMによって実行される。このときfooがreachableとなるためhogeもreachableとなる。(reachable & finalizable)
  • C: fooがunreachableとなり、hogeはfinalizer-reachableに戻る。(finalizer-reachable & finalizable)
  • K: hoge自身のfinalizeメソッドがVMによって実行される。(reachable & finalized)
  • F: どこからも参照されなくなる。(unreachable & finalized)
  • I: ガーベージされる。

L,M,Nの状態遷移は他のオブジェクトがreachableになることで芋づる式に引き起こされるらしいということに今日気づきました。あとまだ良くわかっていないのはD→M→Fへの状態遷移とOの状態遷移。
Oの遷移はおそらく、finalizeをオーバーライドしていないインスタンスに対してはVMはFinalizeインスタンスを作成しない?ので対象のオブジェクト自身はfinalizableになることなくガーベージされるということでしょうか。
問題はD→M→Fの遷移です、と考えたところでイメージ湧きました。こんなかんじだと思います。

  • D: hogeオブジェクトはfinalizeメソッドが実行されたが、まだ他のfinalizableなオブジェクトbarから参照されているのでhogeは「finalizer-reachable & finalized」の状態となる。
  • M: barのfinailizeメソッドが実行される際にhogeは「reachable & finalized」になる。
  • F: hogeに対する参照がなくなったのでhogeは「unreachable & finalized」となる。