Рубрики
Без рубрики

Фантомные ссылки в Java

Узнайте о фантомных ссылках в Java и их распространенных сценариях использования.

Автор оригинала: baeldung.

1. Обзор

В этой статье мы рассмотрим концепцию Фантомной ссылки – на языке Java.

2. Фантомные ссылки

Фантомные ссылки имеют два основных отличия от мягких и слабых ссылок.

Мы не можем получить референт фантомной ссылки. Референт никогда не доступен непосредственно через API, и именно поэтому нам нужен referencequeue для работы с этим типом ссылок.

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

3. Примеры использования

Есть два распространенных варианта использования, для которых они используются.

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

Вторая практика заключается в том, чтобы избежать использования метода finalize и улучшить процесс finalization .

3.1. Пример

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

Во-первых, нам нужен подкласс класса PhantomReference , чтобы определить метод очистки ресурсов:

public class LargeObjectFinalizer extends PhantomReference {

    public LargeObjectFinalizer(
      Object referent, ReferenceQueue q) {
        super(referent, q);
    }

    public void finalizeResources() {
        // free resources
        System.out.println("clearing ...");
    }
}

Теперь мы собираемся написать улучшенную мелкозернистую доработку:

ReferenceQueue referenceQueue = new ReferenceQueue<>();
List references = new ArrayList<>();
List largeObjects = new ArrayList<>();

for (int i = 0; i < 10; ++i) {
    Object largeObject = new Object();
    largeObjects.add(largeObject);
    references.add(new LargeObjectFinalizer(largeObject, referenceQueue));
}

largeObjects = null;
System.gc();

Reference referenceFromQueue;
for (PhantomReference reference : references) {
    System.out.println(reference.isEnqueued());
}

while ((referenceFromQueue = referenceQueue.poll()) != null) {
    ((LargeObjectFinalizer)referenceFromQueue).finalizeResources();
    referenceFromQueue.clear();
}

Во-первых, мы инициализируем все необходимые объекты: ReferenceQueue – для отслеживания ссылок в очереди, references – для последующей очистки, largeObjects – для имитации большой структуры данных.

Затем мы создаем эти объекты с помощью классов Object и Large Object Finalizer .

Перед вызовом сборщика мусора мы вручную освобождаем большой фрагмент данных, разыменовывая список большие объекты . Обратите внимание, что мы использовали ярлык для оператора Runtime.getRuntime().gc() для вызова сборщика мусора.

Важно знать, что System.gc() не запускает сборку мусора сразу – это просто подсказка для JVM, чтобы запустить процесс.

Цикл for демонстрирует, как убедиться, что все ссылки поставлены в очередь – он выведет true для каждой ссылки.

Наконец, мы использовали цикл while , чтобы вытащить ссылки в очереди и выполнить очистку для каждого из них.

4. Заключение

В этом кратком руководстве мы представили фантомные ссылки Java.

Мы узнали, что это такое и как они могут быть полезны в некоторых простых и конкретных примерах.