Почему призрачная ссылка не ставится в очередь?
Я опираюсь на фантомную ссылку, и я запутался, как эта фантомная ссылка ставится в очередь, когда референт собирает мусор.
Вот мой код
Object s = new Object();
ReferenceQueue<Object> queue = new ReferenceQueue<Object>();
PhantomReference<Object> ref = new PhantomReference<Object>(s, queue);
s = null;
System.gc();
TimeUnit.SECONDS.sleep(1);
System.out.println(queue.poll());
Как и ожидалось, queue.poll вернет фантомную ссылку:ref.
Но если я сделаю небольшое изменение в коде: удалите локальную переменную "ref", queue.poll вернет ноль.
Таким образом, я могу сделать вывод, что, когда JVM пытается собрать мусор для объекта, он проверит все ссылки, чтобы увидеть, есть ли какие-либо, которые могут достичь объекта.
Это должно быть очень медленным прогрессом.
Я разработал программу: используйте фантомную ссылку для отслеживания утечки ресурсов. Когда ресурс выделен, фантомная ссылка является новой и привязывается к ресурсу. Затем я обнаружил, что: все фантомные ссылки должны быть сохранены, в противном случае фантомная ссылка не будет помещена в очередь.
И я проверил код netty и обнаружил, что netty хранит все фантомные ссылки:io.netty.util.ResourceLeakDetector#allLeaks.
2 ответа
Как указано в спецификации, "если зарегистрированная ссылка сама по себе становится недоступной, она никогда не будет помещена в очередь". Это, однако, не должно вызывать удивления, так как без достижимого эталонного объекта, который определяет особое состояние достижимости, не существует особого состояния достижимости. Все, что ясно из спецификации, состоит в том, что до тех пор, пока эталонный объект не был поставлен в очередь, нет никакой ссылки из очереди на эталонный объект.
Таким образом, я могу сделать вывод, что, когда JVM пытается собрать мусор для объекта, он проверит все ссылки, чтобы увидеть, есть ли какие-либо, которые могут достичь объекта.
Помимо того, что JVM никогда не пытается собрать один объект, вы только что описали, что такое сборка мусора, пройдя по всем ссылкам, чтобы выяснить, какие объекты еще доступны.
Это должно быть очень медленным прогрессом.
Было бы очень медленно, если бы сборщик мусора делал это снова для каждого объекта. Но сборщик мусора делает обход для всех объектов. Объекты, не встречающиеся во время обхода, являются мусором как таковым, поэтому эти недоступные объекты не нуждаются в какой-либо специальной обработке, которая включает в себя заброшенные ссылочные объекты.
Тем не менее, сборка мусора, конечно же, несет накладные расходы, поэтому System.gc()
не должен вызываться, за исключением случаев отладки, как в примере программы.
Сборщик мусора обрабатывает ссылочный объект как любой другой объект. Из документации:
Если зарегистрированная ссылка сама становится недоступной, она никогда не будет помещена в очередь.
Теоретически, да, использование ссылочных объектов приведет к неэффективности сборки мусора, поэтому я бы не создавал ссылочный объект для каждого объекта приложения. Но на практике набор ссылочных объектов имеет тенденцию быть очень маленьким: они предназначены для отслеживания ресурсов, таких как соединения с базой данных, а не произвольных объектов.