Почему ссылка не помещается в очередь ссылок при переопределении метода 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 ответа

Решение

С нетривиальным finalizeJava знает, что объект недоступен * до 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
Другие вопросы по тегам