Zrozumienie klas referencyjnych języka Java: SoftReference, WeakReference i PhantomReference

81

Czy ktoś może wyjaśnić różnicę między trzema klasami odniesienia (lub zamieścić link do ładnego wyjaśnienia)? SoftReference> WeakReference> PhantomReference, Ale kiedy użyłbym każdy? Dlaczego jest, WeakHashMapale nie ma SoftHashMaplub PhantomHashMap?

A jeśli użyję następującego kodu ...

WeakReference<String> ref = new WeakReference<String>("Hello!");
if (ref != null) {                 // ref can get collected at any time...
    System.gc();                   // Let's assume ref gets collected here.
    System.out.println(ref.get()); // Now what?!
}

...co się dzieje? Muszę sprawdzić, czy refjest null przed każdym rachunku (to jest złe, ale co należy zrobić)? Przepraszam za szybkie pytania, ale mam problem ze zrozumieniem tych Referencezajęć ... Dzięki!

Haywood Jablomey
źródło
1
Dlaczego jest pytanie, WeakHashMapale nie SoftHashMaplub PhantomHashMapdoskonałe, dlaczego wcześniej tego nie zauważyłem .. ??
Mehraj Malik
1
ref != nullCzek nie ma sensu. refnigdy nie będzie null.
Holger
dodanie do P: strongRef --> weakRef --> objA. Teraz będzie objAGCed lub nie, ponieważ ma pośredni odnośnik strongRef.
samshers

Odpowiedzi:

60

Dokumentacja biblioteki Java dla java.lang.refpakietu charakteryzuje malejącą siłę trzech jawnych typów odwołań.

Używasz a, SoftReferencegdy chcesz, aby obiekt, do którego istnieje odwołanie, pozostał aktywny, dopóki proces hosta nie będzie zabrakło pamięci. Obiekt nie będzie kwalifikował się do kolekcji aż kolektor potrzebuje do wolnej pamięci. Luźno sformułowane, wiązanie SoftReferenceoznacza: „Przypnij obiekt, dopóki nie będziesz mógł”.

Z drugiej strony, użyj a, WeakReferencegdy nie chcesz wpływać na czas życia obiektu, do którego się odwołuje; chcesz po prostu zrobić oddzielne stwierdzenie dotyczące obiektu, do którego się odwołujesz, dopóki pozostaje on żywy. Na kwalifikowalność obiektu do odbioru nie ma wpływu obecność związanych elementów WeakReference. Coś w rodzaju zewnętrznego mapowania z instancji obiektu na powiązaną właściwość, gdzie właściwość musi być rejestrowana tylko tak długo, jak powiązany obiekt żyje, jest dobrym zastosowaniem dla WeakReferences i WeakHashMap.

Ten ostatni… - PhantomReferencejest trudniejszy do scharakteryzowania. Na WeakReferenceprzykład takie ograniczenie PhantomReferencenie ma wpływu na żywotność obiektu, do którego się odwołuje. Ale w przeciwieństwie do innych typów referencyjnych, nie można nawet wyłuskać a PhantomReference. W pewnym sensie nie wskazuje na to, na co wskazuje, o ile dzwoniący mogą powiedzieć. Pozwala tylko na powiązanie pewnych powiązanych danych z obiektem, do którego się odwołuje - danymi, które mogą być później sprawdzane i wykonywane, gdy zostaną PhantomReferenceumieszczone w kolejce w powiązanych z nimi obiektach ReferenceQueue. Zwykle typ pochodzi z PhantomReferencetego typu pochodnego i zawiera dodatkowe dane. Niestety, użycie takiego typu pochodnego wymaga pewnych ograniczeń.

W Twoim przykładowym kodzie to nie refodwołanie (lub, jeśli wolisz, „zmienna”), które może mieć wartość null. Jest to raczej wartość uzyskana przez wywołanie, Reference#get()która może być zerowa. Jeśli okaże się, że jest zerowy, jesteś za późno; obiekt, do którego istnieje odwołanie, jest już w drodze do pobrania:

final String val = ref.get();
if (null != val)
{
  // "val" is now pinned strongly.
}
else
{
  // "val" is already ready to be collected.
}
seh
źródło
dodanie do P: strongRef --> weakRef --> objA. Teraz będzie objAGCed lub nie, ponieważ ma pośredni odnośnik strongRef.
samshers
Jeśli dobrze rozumiem twoje pytanie, @samshers objAkwalifikuje się do zbierania jako śmieci. Przypięcie WeakReferencenie ma wpływu na obiekt, na który WeakReferencewskazuje.
seh
Brak silnego odniesienia w łańcuchu ma znaczenie. Ponieważ objAaby plik został wyrzucony jako śmieci, słabe odniesienie musi zostać najpierw usunięte po prawej stronie. Silne odniesienie wskazuje na słabe odniesienie, które sprawia, że ​​słaby ref nie kwalifikuje się do GCed
samshers
Nie, WeakReferencenie trzeba ich odbierać, aby umożliwić objAich pobranie. WeakReferenceNie zachować objAprzy życiu. Jest to raczej sposób na odnalezienie objAgo za życia - bez wpływania na to życie - i wykrycie, kiedy kolekcjoner już go zabrał.
seh
6

Link: https://community.oracle.com/blogs/enicholas/2006/05/04/understanding-weak-references

PhantomHashMapnie działałby zbyt dobrze, ponieważ getzawsze wraca nulldo odniesień fantomowych.

Pamięć podręczna jest trudna, więc SoftHashMapmoże nie działać tak dobrze, jak mogłoby się wydawać. Uważam jednak, że biblioteka kolekcji Google zawiera ogólną implementację mapy referencyjnej.

Powinieneś zawsze sprawdzić, czy getzwraca non- null. (Zwróć uwagę, że nie sprawdzanie, czy Referencesamo odwołanie nie jest… null). W przypadku łańcuchów z internowanymi ciągami tak będzie zawsze, ale (jak zawsze) nie staraj się być „sprytny”.

Tom Hawtin - haczyk
źródło
Link wygasł.
Mehraj Malik
@MehrajMalik Link naprawiony.
Tom Hawtin - tackline
dodanie do P: strongRef --> weakRef --> objA. Teraz będzie objAGCed lub nie, ponieważ ma pośredni odnośnik strongRef.
samshers
0
String str = new String("hello, world");
WeakReference<String> ref = new WeakReference<String>(str);
str = null;

if (ref != null) {                 
    System.gc(); 
    System.out.println(ref.get());
}

W takim przypadku zwróci wartość null. Wezwanie System.gc()jest tutaj ważne.

kopite
źródło