java.lang.ref.Reference
http://d.hatena.ne.jp/taedium/20041215のコメントでid:nminoruさんからまたまたおもしろいことを教えてもらいました。参照オブジェクトはいったんReferenceクラスで一元管理されてからReferenceQueueに入れられるのですね。
どんな風に動くのか、finalizeメソッドを持ったクラスのインスタンスhogeをWeakReferenceとReferenceQueueで管理する場合をイメージしてみました。
Hoge hoge = new Hoge(); (1) ReferenceQueue q = ReferenceQueue(); (2) WeakReference wr = new WeakReference(hoge, q); (3) hoge = null; (4) System.gc(); (5) // このSystem.gc()でgarbage collectionが行われ、 // かつgarbage collectorがhogeをweakly reachableと判断すると仮定する
上のようなコードがあるとして
- まずbootstrap classloaderによるクラスのロードが行われる。
- ReferentクラスがロードされるときReferenceHandlerが動き、Referenceクラスのstaticなpending変数がnullでなくなるまでwait。
- FinalizerクラスがロードされたときFinalizerThreadが動き、FinalizerクラスのstaticなReferenceQueueに値が入るまで待つ。
- (1)のときJavaVMがFinalizerのインスタンスを生成する。
- (2)と(3)でhogeのweakly referenceとqueueを関係付ける。
- (4)でhogeがstrongly reachableでなくなる。
- (5)でgabage collectionがはじまる。
- garbage collectorはhogeをfinalizableと宣言する。このときgarbage collectorは(1)で作成されたFinalizerのインスタンスをReferenceクラスのstaticなpending変数にキューイングする。
- garbage collectorはhogeをweakly reachableと判断する。このときgarbage collectorは(3)でインスタンス化されているWeakReferenceをReferenceクラスのstaticなpending変数にキューイングする。さらにここでWeakReferenceのreferentがclearされる?
- garbage collectionが終わる。
- JavaVMによりReferenceHandlerが起こされる。
- pending変数にキューイングされていたFinalizerがReferenceQueueにenqueueされ、FinalizerThreadが動き出す。
- pending変数にキューイングされていたWeakReferenceがReferenceQueueにenqueueされる。
<疑問>
- WeakReferenceがReferenceQueueにenqueueされたときには必ずしもreferentのfinalize()が実行されているとは限らないみたいです。JavaDocにはfinalizableになるとはあってもfinalize()が実行されるとは書いてないですね。http://www-128.ibm.com/developerworks/java/library/j-refs/index.htmlの「Garbage collector and reference interaction」の節を見るとfinalize()が実行されてからenqueueされるように読めましたが、「After」じゃなくて「When」とあるところがミソなのでしょうか。(ミソって最近言わないかも...)
- WeakReferenceのreferentのclearはどこで行われるかわかりませんでした。アプリケーションがWeakReference#get()を呼び出したときにnullが返るけどまだReferenceQueueにenqueueされていないということが起きてもいいんでしょうか。
- これは疑問ではないですが、到達可能性と参照の強さの概念ってときどきごっちゃになります。