Jedyne, o czym wiem, PhantomReference
to
- Jeśli użyjesz jego
get()
metody, zawsze zwróci,null
a nie obiekt. Jaki z tego pożytek? - Używając
PhantomReference
, upewniasz się, że obiekt nie może zostać wskrzeszony zfinalize
metody.
Ale jaki jest pożytek z tego pojęcia / klasy?
Czy kiedykolwiek używałeś tego w którymś ze swoich projektów lub masz przykład, gdzie powinniśmy to wykorzystać?
FakeReference
lubNonReference
.Odpowiedzi:
Użyłem go
PhantomReference
w uproszczonym, bardzo wyspecjalizowanym rodzaju profilera pamięci do monitorowania tworzenia i niszczenia obiektów. Potrzebowałem ich, aby śledzić zniszczenia. Ale to podejście jest przestarzałe. (Został napisany w 2004 roku z myślą o J2SE 1.4.) Profesjonalne narzędzia do profilowania są znacznie wydajniejsze i bardziej niezawodne, a nowsze funkcje Java 5, takie jak JMX lub agenci i JVMTI, również mogą być używane do tego.PhantomReference
s (używane zawsze razem z kolejką referencyjną) są nadrzędne,finalize
które powodują pewne problemy i dlatego należy ich unikać. Głównie sprawiając, że przedmioty stają się ponownie dostępne. Można tego uniknąć za pomocą idiomu strażnika finalizatora (-> więcej informacji w „Efektywna Java”). Są więc również nową finalizacją .Ponadto
PhantomReference
sI jak psd napisał pierwszy, Roedy Green ma dobre podsumowanie odniesień .
źródło
Ogóle kostkę-up table wyjaśnienie , z Słowniczek Java.
Co oczywiście pokrywa się z dokumentacją PhantomReference :
I na koniec wszystkie krwawe szczegóły ( to dobra lektura ): Java Reference Objects (lub How I Learned to Stop Worrying and Love OutOfMemoryError) .
Miłego kodowania. (Ale żeby odpowiedzieć na pytanie, użyłem tylko WeakReferences.)
źródło
Świetne wyjaśnienie użycia Phantom Reference:
źródło
Znalazłem praktyczny i użyteczny przypadek użycia,
PhantomReference
który znajduje sięorg.apache.commons.io.FileCleaningTracker
w projekcie commons-io.FileCleaningTracker
usunie plik fizyczny, gdy jego obiekt znacznika zostanie usunięty.Warto zwrócić uwagę na
Tracker
klasę, która rozszerzaPhantomReference
klasę.źródło
W JAVA 9 TO POWINNO BYĆ PRZESTARZAŁE!
Użyj
java.util.Cleaner
zamiast tego! (Lubsun.misc.Cleaner
w starszym JRE)Oryginalny post:
Odkryłem, że użycie PhantomReferences ma prawie taką samą liczbę pułapek jak metody finalizujące (ale mniej problemów, gdy dobrze to zrobisz). Napisałem małe rozwiązanie (bardzo mały framework do używania PhantomReferences) dla Javy 8. Pozwala na użycie wyrażeń lambda jako wywołań zwrotnych uruchamianych po usunięciu obiektu. Możesz zarejestrować wywołania zwrotne zasobów wewnętrznych, które powinny zostać zamknięte. Dzięki temu znalazłem rozwiązanie, które działa dla mnie, ponieważ jest znacznie bardziej praktyczne.
https://github.com/claudemartin/java-cleanup
Oto mały przykład pokazujący, jak rejestrowane jest wywołanie zwrotne:
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); }
Jest jeszcze prostsza metoda automatycznego zamykania, działająca mniej więcej tak samo, jak powyżej:
this.registerAutoClose(this.resource);
Aby odpowiedzieć na Twoje pytania:
Nie możesz posprzątać czegoś, co nie istnieje. Ale mógł mieć zasoby, które nadal istnieją i wymagają oczyszczenia, aby można je było usunąć.
Niekoniecznie jest to robić coś innego niż debugowanie / rejestrowanie. A może dla statystyk. Widzę to bardziej jak usługę powiadomień z GC. Możesz również chcieć użyć go do usunięcia zagregowanych danych, które stają się nieistotne po usunięciu obiektu (ale prawdopodobnie są na to lepsze rozwiązania). Przykłady często wspominają o zamknięciu połączeń z bazą danych, ale nie widzę, jak to jest dobry pomysł, ponieważ nie można pracować z transakcjami. Framework aplikacji zapewni znacznie lepsze rozwiązanie tego problemu.
Używam go głównie do logowania. Mogę więc prześledzić usunięte elementy i zobaczyć, jak działa GC i można je dostosować. Nie uruchamiałbym w ten sposób żadnego krytycznego kodu. Jeśli coś wymaga zamknięcia, należy to zrobić w instrukcji try-with-resource. Używam go w testach jednostkowych, aby upewnić się, że nie mam żadnych wycieków pamięci. Tak samo jak robi to jontejj. Ale moje rozwiązanie jest nieco bardziej ogólne.
źródło
Użyłem PhantomReference w teście jednostkowym, aby sprawdzić, czy testowany kod nie zachował niepotrzebnych odwołań do jakiegoś obiektu. ( Oryginalny kod )
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>()); } }
I 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>"); } }
źródło
Często używa się
WeakReference
tam, gdziePhantomReference
jest to bardziej odpowiednie. Pozwala to uniknąć pewnych problemów związanych z wskrzeszaniem obiektów po aWeakReference
wyczyszczeniu / umieszczeniu w kolejce przez moduł odśmiecania pamięci. Zwykle różnica nie ma znaczenia, ponieważ ludzie nie bawią się w głupie robale.Używanie
PhantomReference
wydaje się być nieco bardziej uciążliwe, ponieważ nie można udawać, żeget
metoda działa. Nie możesz na przykład napisać plikuPhantom[Identity]HashMap
.źródło
weakref.get
może zwrócićnull
, a później nadal jest w stanie zwrócić obiekt?finalize
nie odtwarza obiektu jako takiego. Może sprawić, że obiekt będzie ponownie silnie osiągalny poWeakReference
powrocienull
zget
i zostanie umieszczony w kolejce. / (user166390: Tak jak w przypadku mapy z kluczem do celu odniesienia, tak jakWeakHashMap
nie jest to mapa tożsamości odniesień, co jest w porządku.)Przydatnymi metodami do wywołania (zamiast
get()
) byłybyisEnqueued()
lubreferenceQueue.remove()
. Możesz wywołać te metody, aby wykonać jakąś akcję, która musi mieć miejsce podczas ostatniej rundy czyszczenia pamięci obiektu.Za pierwszym razem obiekt ma wywołaną
finalize()
metodę, więc możesz tam również umieścić haczyki zamykające. Jednak, jak stwierdzili inni, prawdopodobnie istnieją bardziej pewne sposoby wykonania czyszczenia lub jakiejkolwiek czynności, która musi zostać wykonana przed i po usunięciu elementów bezużytecznych lub, bardziej ogólnie, po zakończeniu eksploatacji obiektu.źródło
Znalazłem inne praktyczne zastosowanie Jetty
PhantomReferences
w klasie LeakDetector .Jetty używa
LeakDetector
klasy do wykrywania, czy kod klienta pozyskuje zasób, ale nigdy go nie zwalnia, aLeakDetector
klasa używaPhantomReferences
do tego celu.źródło