ReferenceQueue に enqueue されるタイミング
先ほど嵌ったのでエントリ書きます。
Jiemamy のコードを弄って JUnit テストを動かしていたときに気づいたんですが、あるオブジェクトに対して弱参照を行い、参照が切れて GC したはずなのに、ReferenceQueue にそのオブジェクトに対する弱参照インスタンスが enqueue されていないという不可思議な現象が起きました。
もちろん、その参照オブジェクトを弱参照インスタンスから get() しようと思っても、GC されてるので結果は null です。
意味わからんので、ネットで調べてもそれらしい情報にひっかからなかったため、仕方ないので自分で試すことに。
試験的に書いたコードは下記の通り。
public class WeakReferenceTest { public static void main(String[] args) { MyObject myObj = new MyObject(); ReferenceQueue<MyObject> queue = new ReferenceQueue<MyObject>(); Reference<MyObject> ref = new WeakReference<MyObject>(myObj, queue); // 参照を切って GC myObj = null; System.gc(); // ReferenceQueue のチェックと、弱参照インスタンスから get() してみる。 System.out.println(queue.poll()); System.out.println(ref.get()); } private static class MyObject { } }
上記の状態だと、myObj への弱参照を作った上で、生成した myObj への参照を切り、GC するので queue に ref が enqueue される上に、ref.get() の結果は null になるはずです。
で、動かしてみたら。。
null null
え、どっちも null !?
ref.get() の結果は当然なので、納得できます。しかし参照が切れたことを VM が理解してるはずなのになんで queue に enqueue されてないの!?
いろいろ試しましたが、昨晩はよくわからず不貞寝。
で、先ほど起床後いろいろ試したら、ようやく期待する動きになりました。
それが下記のコード。
public class WeakReferenceTest { public static void main(String[] args) throws InterruptedException { MyObject myObj = new MyObject(); ReferenceQueue<MyObject> queue = new ReferenceQueue<MyObject>(); Reference<MyObject> ref = new WeakReference<MyObject>(myObj, queue); // 参照を切って GC myObj = null; System.gc(); Thread.sleep(1000L); // このコードを追加 // ReferenceQueue のチェックと、弱参照インスタンスから get() してみる。 System.out.println(queue.poll()); System.out.println(ref.get()); } private static class MyObject { } }
結果は下記の通り。
java.lang.ref.WeakReference@1a758cb null
1秒待っただけで enqueue されてるとは。。。
あれなんすかね、enqueue されるタイミングとかがあるんですかねぇ。