Java PhantomReference против finalize () - PullRequest
       30

Java PhantomReference против finalize ()

0 голосов
/ 17 декабря 2018

Я читал эту статью о PhantomReference https://www.baeldung.com/java-phantom-reference и упрощенном примере кода, найденном там:

public static void main(String[] args) throws InterruptedException {
    ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
    Object object = new Object();
    PhantomReference<Object> phantomReference = new PhantomReference<>(object, referenceQueue);
    object = null;
    System.gc();
    Thread.sleep(1_000);
    System.out.println("isEnqueued() after GC: " + phantomReference.isEnqueued());
    Reference reference = referenceQueue.poll();
    if(reference != null) {
        System.out.println("isEnqueued() after poll(): " + phantomReference.isEnqueued());
    }
}

Вот вывод:

isEnqueued() after GC: true
isEnqueued() after poll(): false

Так что всеРаботая как ожидалось, для сильной ссылки на объект устанавливается значение null, которое обнаруживается GC, и в очередь добавляется фантомная ссылка.

Теперь в этой статье говорится: «Сборщик мусора добавляет фантомную ссылку к ссылке.очередь после выполнения метода finalize его референта. Это означает, что экземпляр все еще находится в памяти. "

Итак, я хотел создать метод финализации test и override, например:

Object object = new Object() {
    @Override
    protected void finalize() throws Throwable {
        System.out.println("finalize()");
    }
};

Но тогда выходные данные отличаются, фантомная ссылка больше не добавляется в очередь:

finalize()
isEnqueued() after GC: false

Может кто-нибудь объяснить, почему после этого изменения выходные данные отличаются и как изменить этот код, чтобы фантомная ссылка была добавлена ​​в очередь?

Я тестировал это на JDK 8 и 11, одинаковые результаты на обеих платформах.

1 Ответ

0 голосов
/ 18 декабря 2018

Оператор «Сборщик мусора добавляет фантомную ссылку в очередь ссылок после выполнения метода finalize его референта.» В лучшем случае немного небрежно.

Вы должны обратиться к спецификации:

Если сборщик мусора в определенный момент времени определяет, что референт фантомной ссылки фантомно достижим , то в это время или в более позднее времяон будет ставить ссылку в очередь.

В то время как связанное определение «фантомно достижимых» состояний:

Объект фантомно достижим , если он не является ни тем, ни другимсильно, мягко, или слабо достижимо, оно было завершено, и некоторая фантомная ссылка ссылается на него.

Таким образом, объект фантомно доступен «после выполнения метода finalize его референта», если только на него ссылаютсяпо призрачным ссылкам и, следовательно, будет поставлен в очередь после этого , но не сразу .Поскольку объект является сильно достижимым во время выполнения его finalize() метода, требуется по крайней мере один дополнительный цикл сбора мусора, чтобы обнаружить, что он стал фантомно достижимым.Затем «в то время или в более позднее время» он будет поставлен в очередь.

Если вы измените программу на

ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
Object object = new Object() {
    @Override
    protected void finalize() throws Throwable {
        System.out.println("finalize()");
    }
};
PhantomReference<Object> phantomReference = new PhantomReference<>(object, referenceQueue);
object = null;
System.gc();
Thread.sleep(1_000);
System.gc();
Thread.sleep(1_000);
System.out.println("isEnqueued() after GC: " + phantomReference.isEnqueued());
Reference reference = referenceQueue.poll();
if(reference != null) {
    System.out.println("isEnqueued() after poll(): " + phantomReference.isEnqueued());
}

Скорее всего, вы увидите желаемый результат, но он имеетПодчеркнем, что нет никаких гарантий, что сборщик мусора действительно будет работать, когда вы вызываете System.gc(), или что он завершает его определенное количество времени, когда он работает, или что он найдет все недоступные объекты в определенном цикле.Кроме того, постановка в очередь происходит асинхронно после цикла gc, поэтому даже к тому времени, когда сборщик мусора завершит работу и обнаружит особое состояние достижимости, может пройти дополнительное время, прежде чем он будет помещен в очередь.


Обратите внимание, чтопредложение «Это подразумевает, что экземпляр все еще находится в памяти». также не дает правильного представления, но в данном случае оно основано на недоразумении, которое было даже на стороне разработчика ядра Java.

КогдаAPI был создан, в спецификацию было добавлено предложение, которое вы найдете даже в версии для Java 8:

В отличие от мягких и слабых ссылок, фантомные ссылки не очищаются сборщиком мусора автоматически, как онипомещён.Объект, достижимый с помощью фантомных ссылок, будет оставаться таким до тех пор, пока все такие ссылки не будут очищены или сами станут недоступными.

Это может привести к наивному предположению, что объект все еще должен находиться в памяти, но1041 * Спецификация языка Java® гласит:

Могут быть разработаны оптимизирующие преобразования программы, которые уменьшают число достижимых объектов до меньшего, чем те, которые наивно считались бы достижимыми.

Проще говоря, память объектов может быть восстановлена ​​раньше, если поведение программы не изменится.Это особенно относится к сценариям, где приложение вообще не может использовать объект, как в случае с фантомной ссылкой.Поведение программы не изменилось бы, если бы объект больше не находился в памяти, поэтому вы не можете предполагать, что это на самом деле.

Это приводит к вопросу, почему правило, по которому не удаляются фантомные ссылки, былодобавил в спецификации вообще.Как обсуждалось в этом ответе , этот вопрос был поднят и не мог быть дан вообще.Следовательно, это правило было удалено в Java 9, и фантомные ссылки очищаются, когда ставятся в очередь как слабые и мягкие ссылки.Это еще более веская причина не предполагать, что объект все еще находится в памяти, поскольку теперь даже неоптимизирующие среды могут восстановить память объекта в этот момент.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...