Призрачные ссылки на Java

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

1. обзор

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

2. Призрачные Ссылки

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

We can’t get a referent of a phantom reference. Референт никогда не доступен напрямую через API, и именно поэтому нам нужна очередь ссылок для работы с этим типом ссылок.

Сборщик мусора добавляет фантомную ссылку в очередь ссылокafter the finalize method of its referent is executed. Это означает, что экземпляр все еще находится в памяти.

3. Случаи применения

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

Первый метод -to determine when an object was removed from the memory, который помогает планировать задачи, связанные с памятью. Например, мы можем подождать, пока большой объект будет удален, прежде чем загружать другой.

Вторая практика -to avoid using the finalize method and improve thefinalization process.

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 иLargeObjectFinalizer.

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

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

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

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

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

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

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