Вы когда-нибудь использовали PhantomReference в любом проекте?

Единственное, что я знаю о PhantomReference, это

  • Если вы используете метод get(), он всегда будет возвращать null, а не объект. Какая польза от этого?
  • Используя PhantomReference, вы убедитесь, что объект не может быть воскрешен из метода finalize.

Но каково использование этого понятия/класса?

Вы когда-либо использовали это в любом из своих проектов или у вас есть какой-то пример, где мы должны это использовать?

Ответ 1

Я использовал PhantomReference в упрощенном, очень специализированном профиле профилей памяти для мониторинга создания и уничтожения объектов. Мне нужно, чтобы они следили за уничтожением. Но подход устарел. (Это было написано в 2004 году, ориентированное на J2SE 1.4.) Профессиональные инструменты профилирования гораздо более мощные и надежные, и для этого также могут использоваться более новые функции Java 5, такие как JMX или агенты и JVMTI.

PhantomReference (всегда используется вместе со ссылочной очередью) превосходит finalize, который имеет некоторые проблемы и поэтому следует избегать. Главным образом сделать объекты доступными снова. Этого можно избежать с помощью идентификатора опекуна финализатора (- > больше в "Эффективной Java" ). Таким образом, они также являются новой финализацией.

Кроме того, PhantomReference s

позволяет точно определить, когда объект был удален из памяти. Oни на самом деле единственный способ определить это. Обычно это не так полезно, но может пригодиться в определенных очень специфических обстоятельствах например, манипулирование большими изображениями: если вы точно знаете, что изображение должно быть собранный мусор, вы можете подождать, пока он на самом деле не появится. загрузите следующее изображение и, следовательно, сделайте страшный OutOfMemoryError менее вероятно. (Цитируется из enicholas.)

И как psd написал первый, Roedy Green имеет хорошее резюме ссылок.

Ответ 2

A общее объяснение таблицы фактов из глоссария Java.

Что, конечно, совпадает с документацией PhantomReference:

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

И последнее, но не менее важное: все детали gory (это хорошее чтение): Справочные объекты Java (или как я научился перестать волноваться и любить OutOfMemoryError ).

Счастливое кодирование. (Но чтобы ответить на вопрос, я только когда-либо использовал WeakReferences.)

Ответ 3

Я нашел практический и полезный вариант использования PhantomReference, который org.apache.commons.io.FileCleaningTracker в проекте commons-io. FileCleaningTracker удалит физический файл, когда его объект-маркер будет собран мусором.
Следует отметить класс Tracker, который расширяет класс PhantomReference.

Ответ 4

Отличное объяснение Phantom Использование ссылок:

Phantom ссылки - это безопасный способ узнать, что объект удален из памяти. Например, рассмотрите приложение, которое имеет дело с большими изображениями. Предположим, что мы хотим загрузить большое изображение в память, когда большое изображение уже находится в памяти, которое готово для сбора мусора. В таком случае мы хотим подождать, пока старый файл не будет собран до загрузки нового. Здесь ссылка Phantom является гибкой и безопасной выборкой. Ссылка на старое изображение будет выделена в ReferenceQueue после завершения старого объекта изображения. После получения этой ссылки мы можем загрузить новое изображение в память.

Ответ 5

Я использовал PhantomReference в unit test, чтобы убедиться, что тестируемый код не сохранил неосновательные ссылки на какой-либо объект. (Исходный код)

import static com.google.common.base.Preconditions.checkNotNull;
import static org.fest.assertions.Assertions.assertThat;

import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;

import com.google.common.testing.GcFinalization;

/**
* Helps to test for memory leaks
*/
public final class MemoryTester
{
private MemoryTester()
{
}

/**
* A simple {@link PhantomReference} that can be used to assert that all references to it is
* gone.
*/
public static final class FinalizationAwareObject extends PhantomReference<Object>
{
private final WeakReference<Object> weakReference;

private FinalizationAwareObject(Object referent, ReferenceQueue<Object> referenceQueue)
{
super(checkNotNull(referent), referenceQueue);
weakReference = new WeakReference<Object>(referent, referenceQueue);
}

/**
* Runs a full {@link System#gc() GC} and asserts that the reference has been released
* afterwards
*/
public void assertThatNoMoreReferencesToReferentIsKept()
{
String leakedObjectDescription = String.valueOf(weakReference.get());
GcFinalization.awaitFullGc();
assertThat(isEnqueued()).as("Object: " + leakedObjectDescription + " was leaked").isTrue();
}
}

/**
* Creates a {@link FinalizationAwareObject} that will know if {@code referenceToKeepTrackOff}
* has been garbage collected. Call
* {@link FinalizationAwareObject#assertThatNoMoreReferencesToReferentIsKept()} when you expect
* all references to {@code referenceToKeepTrackOff} be gone.
*/
public static FinalizationAwareObject createFinalizationAwareObject(Object referenceToKeepTrackOff)
{
return new FinalizationAwareObject(referenceToKeepTrackOff, new ReferenceQueue<Object>());
}
}

И test:

@Test
public void testThatHoldingOnToAnObjectIsTreatedAsALeak() throws Exception
{
    Object holdMeTight = new String("Hold-me-tight");
    FinalizationAwareObject finalizationAwareObject = MemoryTester.createFinalizationAwareObject(holdMeTight);
    try
    {
    finalizationAwareObject.assertThatNoMoreReferencesToReferentIsKept();
    fail("holdMeTight was held but memory leak tester did not discover it");
    }
    catch(AssertionError expected)
    {
    assertThat(expected).hasMessage("[Object: Hold-me-tight was leaked] expected:<[tru]e> but was:<[fals]e>");
    }
}

Ответ 6

ЭТО ДОЛЖНО БЫТЬ ОБОРОМЕТОМ С JAVA 9!
Используйте java.util.Cleaner вместо этого! (Или sun.misc.Cleaner на старшей JRE)

Оригинальное сообщение:


Я обнаружил, что использование PhantomReferences имеет почти такое же количество ловушек, что и методы финализатора (но с меньшими проблемами, когда вы правильно это понимаете). Я написал небольшое решение (очень небольшую основу для использования PhantomReferences) для Java 8. Он позволяет использовать лямбда-выражения в качестве обратных вызовов, которые будут выполняться после удаления объекта. Вы можете зарегистрировать обратные вызовы для внутренних ресурсов, которые должны быть закрыты. С этим я нашел решение, которое работает для меня, поскольку оно делает его гораздо более практичным.

https://github.com/claudemartin/java-cleanup

Вот небольшой пример, показывающий, как зарегистрирован обратный вызов:

  class Foo implements Cleanup {
    //...  
    public Foo() { 
    //...    
      this.registerCleanup((value) -> {
        try {
          // 'value' is 'this.resource'
          value.close();
        } catch (Exception e) {
          logger.warning("closing resource failed", e);
        }
      }, this.resource);
    }

И тогда есть еще более простой метод автоматического закрытия, делая примерно то же самое, что и выше:

this.registerAutoClose(this.resource);

Чтобы ответить на ваши вопросы:

[то, что его использует]

Вы не можете очистить то, чего не существует. Но у него могли быть ресурсы, которые все еще существуют, и их необходимо очистить, чтобы их можно было удалить.

Но каково использование этого понятия/класса?

Это не обязательно делать ничего с каким-либо эффектом, кроме отладки/регистрации. Или, может быть, для статистики. Я вижу, что это больше похоже на службу уведомления из GC. Вы также можете использовать его для удаления агрегированных данных, которые становятся неактуальными после удаления объекта (но, вероятно, для этого есть лучшие решения). В примерах часто упоминаются подключения к базе данных, которые нужно закрыть, но я не вижу, как это такая хорошая идея, как вы не могли бы работать с транзакциями. Рамка приложений обеспечит гораздо лучшее решение для этого.

Вы когда-либо использовали это в любом из своих проектов, или у вас есть какой-нибудь пример, где мы должны это использовать? Или это понятие сделано только для интервью точки зрения;)

Я использую его в основном только для ведения журнала. Поэтому я могу отслеживать удаленные элементы и видеть, как работает GC и может быть изменен. Таким образом, я не буду запускать критический код. Если что-то нужно закрыть, это должно быть сделано в try-with-resource-statement. И я использую его в модульных тестах, чтобы убедиться, что у меня нет утечек памяти. Точно так же, как и jontejj. Но мое решение немного более общее.

Ответ 7

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

Использование PhantomReference имеет тенденцию быть немного более интрузивным, потому что вы не можете притворяться, что работает метод get. Вы не можете, например, написать Phantom[Identity]HashMap.

Ответ 8

если вы используете метод get(), он всегда будет возвращать значение null, а не объект. [тогда зачем это использовать]

Полезные методы вызова (а не get()) будут isEnqueued() или referenceQueue.remove(). Вы бы назвали эти методы для выполнения некоторых действий, которые должны выполняться в последнем раунде сборки мусора объекта.

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