Вы когда-нибудь использовали PhantomReference в каком-либо проекте?
единственное, что я знаю о PhantomReference
есть
- если вы используете его
get()
метод, он всегда будет возвращатьnull
а не объект. Какой в этом смысл? - С помощью
PhantomReference
, вы убедитесь, что объект не может быть воскрешен изfinalize
метод.
но в чем польза этого понятия/класса?
вы когда-нибудь использовали это в любом из ваших проектов или у вас есть любой пример, где мы должны использовать это?
8 ответов:
Я
PhantomReference
с упрощенный, очень специализированный вид профилировщика памяти мониторинг создания и уничтожения объектов. Мне нужно было, чтобы они следили за разрушениями. Но этот подход устарел. (Он был написан в 2004 году для J2SE 1.4.) Профессиональные инструменты профилирования являются гораздо более мощными и надежными, и для этого также могут использоваться новые функции Java 5, такие как JMX или агенты и JVMTI.
PhantomReference
s (всегда используется вместе со ссылочной очередью) являются превосходитfinalize
, который имеет некоторые проблемы, и поэтому их следует избегать. В основном делает объекты доступными снова. Этого можно было бы избежать с помощью идиомы finalizer guardian (- >подробнее в разделе "эффективная Java"). Так что они тоже new finalize.кроме того,
PhantomReference
sпозволяет точно определить, когда объект был удален из памяти. Они на самом деле это единственный способ определить это. Это вообще не то полезно, но может пригодиться в определенных, очень специфических обстоятельствах как манипулирование большими изображениями: если вы точно знаете, что изображение должно быть мусора, вы можете подождать, пока он на самом деле, прежде чем пытаться загрузить следующее изображение, и, следовательно, сделать страшный исключение OutOfMemoryError меньше скорее всего. (Цитата из enicholas.)
и psd написал сначала, у Роуди Грина есть хорошее резюме ссылки.
A общее объяснение таблицы кубиков, из глоссария Java.
Что, конечно, совпадает с документация PhantomReference:
фантомные ссылочные объекты, которые ставятся в очередь после того, как коллектор определит, что их референты могут быть восстановлены в противном случае. Фантомные ссылки чаще всего используются для планирования действий по предсмертной очистке более гибким способом, чем это возможно с завершением Java механизм.
и последнее, но не менее важное, все кровавые детали (это хорошо читать):Java Reference Objects (или как я научился перестать беспокоиться и любить OutOfMemoryError).
удачи в кодировании. (Но чтобы ответить на вопрос, я всегда использовал только слабые ссылки.)
я нашел практический и полезный случай использования
PhantomReference
что этоorg.apache.commons.io.FileCleaningTracker
в проекте commons-io.FileCleaningTracker
удалит физический файл, когда его объект маркера будет собран мусор.
Что-то принять к сведению этоTracker
класс, который расширяетсяPhantomReference
класса.
объяснение фантомного использования ссылки:
фантомные ссылки-это безопасный способ узнать, что объект был удален из памяти. Например, рассмотрим приложение, которое имеет дело с большое изображение. Предположим, что мы хотим загрузить большое изображение в памяти когда большое изображение уже находится в памяти, которая готова для мусора собранный. В таком случае мы хотим дождаться, пока старый образ будет собранный перед загрузкой новый. Вот, призрак ссылка гибкий и безопасный вариант для выбора. Ссылка на старый образ будет поставлен в очередь в ReferenceQueue как только старый объект изображения доработанный. После получения этой ссылки мы можем загрузить новое изображение на память.
Я использовал PhantomReference в модульном тесте, чтобы проверить, что тестируемый код не содержит ненужных ссылок на какой-либо объект. (исходный код)
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 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>"); } }
ЭТО ДОЛЖНО БЫТЬ УСТАРЕВШИМ С 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 работает и может быть изменен. Я бы не стал запускать критический код таким образом. Если что-то должно быть закрыто, то это должно быть сделано в try-with-resource-statement. И я использую его в модульных тестах, чтобы убедиться, что у меня нет утечек памяти. Так же, как это делает йонтейдж. Но мое решение немного больше генеральный.
он является общим, чтобы использовать
WeakReference
здесьPhantomReference
более уместен. Это позволяет избежать некоторых проблем с возможностью воскрешения объектов послеWeakReference
очищается / ставится в очередь сборщиком мусора. Обычно разница не имеет значения, потому что люди не играют в глупых педерастов.используя
PhantomReference
имеет тенденцию быть немного более навязчивым, потому что вы не можете притворяться, чтоget
метод работает. Вы не можете, например, написатьPhantom[Identity]HashMap
.
если вы используете его метод get (), он всегда будет возвращать null, а не объект. [ тогда какой в этом смысл]
полезные методы для вызова (а не
get()
) будетisEnqueued()
илиreferenceQueue.remove()
. Вы могли бы вызвать эти методы для выполнения некоторых действий, которые должны иметь место на заключительном раунде сборки мусора объекта.первый раз, когда объект имеет свой
finalize()
метод вызван, так что вы можете поставить закрывающие крючки там тоже. Однако, как утверждали другие, есть, вероятно, более надежные способы выполнения очистки или любых действий, которые необходимо выполнить до и после сбора мусора или, в более общем плане, по окончании срока службы объекта.