Я знаю только одно PhantomReference
,
- Если вы используете его
get()
метод, он всегда будет возвращать,null
а не объект. Какая от этого польза? - Используя
PhantomReference
, вы убедитесь, что объект нельзя воскресить изfinalize
метода.
Но какова польза от этого понятия / класса?
Вы когда-нибудь использовали это в каком-либо из своих проектов или у вас есть какой-нибудь пример, где мы должны это использовать?
FakeReference
илиNonReference
.Ответы:
Я использовал
PhantomReference
s в упрощенном, очень специализированном профилировщике памяти для отслеживания создания и уничтожения объектов. Мне они были нужны, чтобы отслеживать разрушения. Но подход устарел. (Он был написан в 2004 году для J2SE 1.4.) Профессиональные инструменты профилирования намного мощнее и надежнее, и для этого также можно использовать новые функции Java 5, такие как JMX или агенты и JVMTI.PhantomReference
s (всегда используется вместе с очередью ссылок) лучше,finalize
чем с некоторыми проблемами, и поэтому их следует избегать. В основном делая объекты снова доступными. Этого можно было избежать с помощью идиомы-хранителя финализатора (-> подробнее см. «Эффективная Java»). Так они и в новой доработке .Кроме того,
PhantomReference
sИ, как первым написал psd , у Роеди Грина есть хорошее резюме ссылок .
источник
Целом нарезанная таблица объяснение , из Java Глоссария.
Что, конечно, совпадает с документацией PhantomReference :
И последнее, но не менее важное, все кровавые подробности ( это хорошее чтение ): ссылочные объекты Java (или Как я научился перестать беспокоиться и полюбить OutOfMemoryError) .
Удачного кодирования. (Но чтобы ответить на вопрос, я когда-либо использовал только WeakReferences.)
источник
Отличное объяснение использования Phantom Reference:
источник
Я нашел практический и полезный вариант использования,
PhantomReference
который естьorg.apache.commons.io.FileCleaningTracker
в проекте commons-io.FileCleaningTracker
удалит физический файл, когда его объект-маркер будет удален.Следует обратить внимание на
Tracker
класс, расширяющийPhantomReference
класс.источник
ЭТО ДОЛЖНО БЫТЬ УСТАРЕЛО В 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. И я использую его в модульных тестах, чтобы убедиться, что у меня нет утечек памяти. Так же, как это делает jontejj. Но мое решение более общее.
источник
Я использовал 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>"); } }
источник
Обычно используется
WeakReference
там, гдеPhantomReference
это более удобно. Это позволяет избежать некоторых проблем, связанных с возможностью воскрешать объекты после того, как объектWeakReference
будет очищен / поставлен в очередь сборщиком мусора. Обычно разница не имеет значения, потому что люди не играют в глупых жук.Использование
PhantomReference
имеет тенденцию быть немного более навязчивым, потому что вы не можете притвориться, чтоget
метод работает. Вы не можете, например, написатьPhantom[Identity]HashMap
.источник
weakref.get
может вернутьсяnull
, а потом он все еще может вернуть obj?finalize
не воссоздает объект как таковой. Это может сделать объект сильно достижимым снова послеWeakReference
возвращенияnull
изget
и помещён. / (user166390: Как и на карте, привязанной к цели ссылки, как и вWeakHashMap
случае с картой идентичности ссылок, и это нормально.)Полезными методами для вызова (а не
get()
) были быisEnqueued()
илиreferenceQueue.remove()
. Вы могли бы вызвать эти методы, чтобы выполнить какое-либо действие, которое должно произойти в последнем цикле сборки мусора объекта.В первый раз это происходит, когда у объекта вызывается его
finalize()
метод, поэтому вы также можете поместить туда закрывающие крючки. Однако, как утверждали другие, вероятно, существуют более надежные способы выполнения очистки или любого другого действия, которое необходимо выполнить до и после сборки мусора или, в более общем плане, по окончании срока службы объекта.источник
Я нашел другое практическое применение
PhantomReferences
в классе LeakDetector Jetty.Jetty использует
LeakDetector
класс, чтобы определить, получает ли клиентский код ресурс, но никогда не освобождает его, иLeakDetector
класс используетPhantomReferences
для этой цели.источник