WeakReferenceを作る時にReferenceQueueを渡して、System.gc();しても、すぐにReferenceQueueに入らないんだけど!って話をどっかで見たので。
うまくいくときといかないときがあるときはスレッドを疑えってばっちゃが言ってた。
C:\Users\ryozi>java -version
java version "1.8.0_05"
Java(TM) SE Runtime Environment (build 1.8.0_05-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.5-b02, mixed mode)
Referenceを使うと、裏でReferenceHandlerってThreadが動く。
これはReferenceクラスのstaticブロック中で作ってる。
通常はずっとwaitしているだけなのだけど、GCによってReference先のインスタンスが回収された(?)タイミングでnotify()を受けるのか、突然動き出し、
ReferenceオブジェクトをQueueに入れようとする。
だから、別スレッドで動いてるからCPUのご機嫌次第で一瞬でキューに入ったり、なかなか入らなかったりする。
Referenceクラスの以下の箇所をブレイクポイントで止めてしまうと、ずっとキューに入らない。
java.lang.ref.Reference
public void run() { for (;;) { Reference r; synchronized (lock) { if (pending != null) { r = pending; pending = r.discovered; r.discovered = null; } else { try { lock.wait(); } catch (InterruptedException x) { } continue; } } // Fast path for cleaners if (r instanceof Cleaner) { ### <= ここにブレイクポイントを置いておく ((Cleaner)r).clean(); continue; } ReferenceQueue q = r.queue; if (q != ReferenceQueue.NULL) q.enqueue(r); } } }
サンプルコード
public class WeakReferenceSample { /** * @param args * @throws InterruptedException */ public static void main(String[] args) throws InterruptedException { ReferenceQueue<String> refQueue = new ReferenceQueue<String>(); WeakReference<String> stringRef = new WeakReference<String>(new String("HOGE"), refQueue); System.gc(); int count = 0; while (refQueue.poll() == null) { System.out.println("poll failed. count=" + (++count)); } System.out.println("END"); } }
ずっとカウンタが増え続けていく様子がみれるはず。