Почему ссылка не помещается в очередь ссылок при переопределении метода finalize
public class Test {
public static void main(String[] args) throws Exception {
A aObject = new A();
ReferenceQueue<A> queue = new ReferenceQueue<>();
PhantomReference<A> weak = new PhantomReference<>(aObject, queue);
aObject = null;
System.gc();
TimeUnit.SECONDS.sleep(1);
System.out.println(queue.poll());
}
}
class A{
@Override
protected void finalize() throws Throwable {
// TODO Auto-generated method stub
super.finalize();
System.out.println("finalize");
}
}
Результат:
finalize
null
но если я удалю метод finalize в классе A, результат будет:
java.lang.ref.PhantomReference@5b2c9e5d
итак, результат показывает, что когда я перезаписываю метод finalize, слабый объект не помещается в очередь ссылок, это потому, что aObject воскрес? Но я ничего не делаю в методе финализации
2 ответа
С нетривиальным finalize
Java знает, что объект недоступен * до finalize
работает, но он не знает, что объект все еще недоступен после finalize
,
Он должен ждать, пока объект не будет снова считаться недоступным в другом цикле GC, прежде чем он сможет поставить в очередь фантомную ссылку.
* не совсем недоступен в терминологии документов java.lang.ref, но не доступен ни сильно, ни мягко, ни слабо
Очень интересное наблюдение. Вот что происходит:
Когда класс имеет нетривиальный (непустой в случае OP) finalize
Метод JVM создаст java.lang.ref.Finalizer
(который является подклассом Reference
) объект и указать его нашему референту, в данном случае объект. Это в свою очередь предотвратит PhantomReference
поставить в очередь, так как А уже упоминается Finalizer
,
Это было мной наблюдателем в отладчике с использованием Java 1.8, а также подробно описано здесь.
Наблюдение от @Turing85 ожидается, так как, когда мы удаляем все утверждения внутри finalize
метод становится тривиальным и ведет себя так же, как любой класс без finalize
метод и не будет ссылаться на Finalizer
,
Обновить:
Вопрос был задан, если Finalizer
очистит свою ссылку на A вообще. JVM очищает его при последующих запусках GC, что, в свою очередь, позволяет PhantomReference
поставить A в очередь ссылок.
Например, запуск приведенного ниже кода с нетривиальным finalize
метод получит ненулевое значение PhantomReference
из своей справочной очереди.
public static void main(String[] args) throws Exception {
A aObject = new A();
ReferenceQueue<A> queue = new ReferenceQueue<>();
PhantomReference<A> pr = new PhantomReference<>(aObject, queue);
aObject = null;
System.gc();
TimeUnit.SECONDS.sleep(1);
System.gc();
TimeUnit.SECONDS.sleep(1);
System.out.println( queue.poll() );
}
Печать:
finalize
java.lang.ref.PhantomReference@15db9742