Я пытаюсь использовать ReferenceQueue для освобождения ресурсов, используемых объектами сбора мусора. Проблема в том, что моя ссылочная очередь всегда пуста, даже если есть доказательство того, что один из ссылочных объектов был собран мусором. Вот очень простой, автономный тест JUnit, который иллюстрирует то, что я пытаюсь сделать (отслеживать удаление объекта):Почему ReferenceQueue всегда пуст?
@Test
public void weakReferenceTest() {
ReferenceQueue<Object> refQueue = new ReferenceQueue<Object>();
Object myObject1 = new Object();
Object myObject2 = new Object();
WeakReference<Object> ref1 = new WeakReference<Object>(myObject1, refQueue);
WeakReference<Object> ref2 = new WeakReference<Object>(myObject2, refQueue);
myObject1 = null;
// simulate the application running and calling GC at some point
System.gc();
myObject1 = ref1.get();
myObject2 = ref2.get();
if (myObject1 != null) {
System.out.println("Weak Reference to MyObject1 is still valid.");
fail();
} else {
System.out.println("Weak Reference to MyObject1 has disappeared.");
}
if (myObject2 != null) {
System.out.println("Weak Reference to MyObject2 is still valid.");
} else {
System.out.println("Weak Reference to MyObject2 has disappeared.");
fail();
}
Reference<? extends Object> removedRef = refQueue.poll();
boolean trackedRemoval = false;
while (removedRef != null) {
if (removedRef == ref1) {
System.out.println("Reference Queue reported deletion of MyObject1.");
trackedRemoval = true;
} else if (removedRef == ref2) {
System.out.println("Reference Queue reported deletion of MyObject2.");
fail();
}
removedRef = refQueue.poll();
}
if (trackedRemoval == false) {
fail();
}
}
Для меня это всегда печатает:
Weak Reference to MyObject1 has disappeared.
Weak Reference to MyObject2 is still valid.
.. . Это нормально, но тест всегда терпит неудачу из-за того, что trackedRemoval
находится на false
в конце - ReferenceQueue
всегда пуст.
Я использую ReferenceQueue
и/или WeakReference
s неправильно? Я также попробовал PhantomReference
s, но это не имеет значения.
Интересно, что если вы конвертируете Unit Test в обычный метод public static void main(String[] args)
, то он работает как шарм!
Может ли кто-нибудь объяснить это конкретное поведение? Я давно искал ответ на этот вопрос.
«В то же время или * в какое-то позднее время * он будет выставлять в очередь те недавно очищенные слабые ссылки, которые зарегистрированы в контрольных очередях». Это означает, что JVM разрешено делать крайне сумасшедшие вещи, помещая ссылку в ссылочную очередь. – hexafraction
IIRC it * обычно * происходит, когда GC снова вызывается. Причина - это, скорее всего, эффективность, но я не знаю точного механизма. – maaartinus
@hexafraction: Вы правы, теоретически это может потребоваться навсегда для того, чтобы объект был помещен в Очередь ссылок. Но опять же, для чего еще нужен этот механизм? – Alan47