Jaka jest różnica między java.lang.ref.WeakReference
i java.lang.ref.SoftReference
?
Jaka jest różnica między java.lang.ref.WeakReference
i java.lang.ref.SoftReference
?
Odpowiedzi:
Ze zrozumienia słabych referencji Ethana Nicholasa:
Słabe referencje
Słaby odniesienia , po prostu, jest odniesienie że nie jest wystarczająco silny, aby zmusić obiekt pozostanie w pamięci. Słabe referencje pozwalają ci wykorzystać zdolność śmieciarza do określenia twojej osiągalności, więc nie musisz tego robić sam. Tworzysz słabe odniesienie, takie jak to:
WeakReference weakWidget = new WeakReference(widget);
a następnie w innym miejscu w kodzie można użyć
weakWidget.get()
do uzyskania rzeczywistegoWidget
obiektu. Oczywiście słabe odwołanie nie jest wystarczająco silne, aby zapobiec wyrzucaniu elementów bezużytecznych, więc możesz znaleźć (jeśli nie ma silnych odniesień do widżetu), któryweakWidget.get()
nagle zaczyna wracaćnull
....
Miękkie odniesienia
Miękkie odniesienia jest dokładnie jak słaby odniesienia, z tym że jest to mniej chętnie wyrzucić obiekt, do którego się odnosi. Obiekt, który jest tylko słabo osiągalny (najsilniejsze odniesienia do niego
WeakReferences
), zostanie odrzucony w następnym cyklu wyrzucania elementów bezużytecznych, ale obiekt, do którego można łatwo dotrzeć, na ogół pozostanie na chwilę.
SoftReferences
nie muszą zachowywać się inaczej niżWeakReferences
, ale w praktyce obiekty łatwo osiągalne są na ogół zatrzymywane, dopóki pamięć jest bogata. To sprawia, że są doskonałym fundamentem pamięci podręcznej, takiej jak pamięć podręczna obrazów opisana powyżej, ponieważ możesz pozwolić śmieciarzowi martwić się zarówno o to, jak osiągalne są obiekty (silnie osiągalny obiekt nigdy nie zostanie usunięty z pamięci podręcznej), a także jak źle potrzebuje pamięci, którą zużywają.
I Peter Kessler dodał w komentarzu:
Środowisko JRE firmy Sun traktuje SoftReferences inaczej niż WeakReferences. Próbujemy trzymać się obiektu, do którego odwołuje się SoftReference, jeśli nie ma presji na dostępną pamięć. Jeden szczegół: zasady dla środowiska JRE „-client” i „-server” są różne: środowisko JRE -client próbuje utrzymać mały ślad, woląc wyczyścić SoftRefereferencje niż rozwinąć stertę, podczas gdy środowisko JRE -server próbuje zachować wysoka wydajność, woląc rozwinąć stertę (jeśli to możliwe) niż wyczyścić SoftReferences. Jeden rozmiar nie pasuje do wszystkich.
Słabe referencje są gromadzone chętnie. Jeśli GC stwierdzi, że obiekt jest słabo osiągalny (osiągalny tylko przez słabe odniesienia), natychmiast usunie słabe odniesienia do tego obiektu. Jako takie, są dobre do przechowywania odniesienia do obiektu, dla którego twój program również przechowuje (silnie odwoływane) „powiązane informacje” gdzieś, takie jak buforowane informacje o odbiciu dotyczące klasy lub opakowanie obiektu itp. Wszystko, co tworzy nie ma sensu zachowywać się po obiekcie, z którym jest skojarzony, jest GC-ed. Kiedy słabe odniesienie zostanie usunięte, zostanie umieszczone w kolejce w kolejce referencyjnej, w której twój kod odpytuje gdzieś, i odrzuca również powiązane obiekty. Oznacza to, że przechowujesz dodatkowe informacje o obiekcie, ale informacje te nie są potrzebne, gdy obiekt, do którego się odnosi, zniknie. Tak właściwie, w niektórych sytuacjach można nawet podklasować WeakReference i zachować powiązane dodatkowe informacje o obiekcie w polach podklasy WeakReference. Innym typowym zastosowaniem WeakReference jest połączenie z Mapami do przechowywania instancji kanonicznych.
Z drugiej strony SoftReferences są dobre do buforowania zewnętrznych zasobów, które można odzyskać, ponieważ GC zwykle opóźnia ich usunięcie. Jest jednak pewne, że wszystkie SoftRefereferencje zostaną usunięte przed zgłoszeniem OutOfMemoryError, więc teoretycznie nie mogą spowodować OOME [*].
Typowym przykładem użycia jest przechowywanie przeanalizowanej formy zawartości z pliku. Wdrożysz system, w którym ładujesz plik, parsujesz go i przechowujesz SoftReference do obiektu głównego analizowanej reprezentacji. Następnym razem, gdy będziesz potrzebować pliku, spróbujesz go odzyskać poprzez SoftReference. Jeśli możesz go odzyskać, oszczędziłeś sobie kolejnego ładowania / analizy, a jeśli GC wyczyściło go w międzyczasie, przeładujesz go. W ten sposób wykorzystujesz wolną pamięć do optymalizacji wydajności, ale nie ryzykujesz OOME.
Teraz dla [*]. Utrzymywanie SoftReference nie może samo w sobie powodować OOME. Jeśli z drugiej strony omyłkowo użyjesz SoftReference do zadania, do którego należy użyć WeakReference (tzn. Zachowasz informacje powiązane z obiektem w jakiś sposób silnie przywołane i odrzucisz je, gdy obiekt odniesienia zostanie wyczyszczony), możesz uruchomić OOME jako Twój kod, który odpytuje ReferenceQueue i odrzuci powiązane obiekty, może nie działać w odpowiednim czasie.
Tak więc decyzja zależy od użycia - jeśli buforujesz informacje, które są drogie w budowie, ale mimo to można je odtworzyć z innych danych, użyj miękkich odniesień - jeśli trzymasz odniesienie do kanonicznej instancji niektórych danych lub chcesz mieć odniesienie do obiektu bez „posiadania go” (tym samym uniemożliwiając GC'd), użyj słabego odniesienia.
WeakReference
jest to, że w miejscach, w których należy go używać, fakt, że można zachować ważność przez chwilę po tym, jak odniesienie wykracza poza zakres, może być dopuszczalny, ale nie jest pożądany.
WeakReference
aby obserwować działania GC. Patrz opracowanie: stackoverflow.com/a/46291143/632951
W Javie ; porządek od najsilniejszego do najsłabszego, są to: Strong, Soft, Weak i Phantom
Wyraźne odniesienie jest normalną odniesienia, który chroni określonego obiektu ze zbioru za pomocą GC. tj. Nigdy nie zbiera śmieci.
Odniesienia Miękkie jest uprawniony do odbioru przez śmieciarza, lecz prawdopodobnie nie zostaną zebrane, aż potrzebna jest jego pamięć. tj. śmieci są zbierane wcześniej OutOfMemoryError
.
Słaby odniesienia jest punktem odniesienia, który nie odwołuje się do ochrony obiektu ze zbioru za pomocą chromatografii gazowej. tzn. śmieci są zbierane, gdy nie ma silnych lub miękkich ref.
Odniesienia Phantom jest odniesienie do obiektu jest określany po phantomly została sfinalizowana, ale przed jej przydzielona pamięć została odzyskana.
Analogia: Załóżmy, że JVM to królestwo, Object to król królestwa, a GC to atakujący królestwo, który próbuje zabić króla (obiekt).
until memory is available
nie ma sensu. Czy masz na myśli is eligible for collection by garbage collector, but probably won't be collected until its memory is needed for another use
?
Słabe referencje http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/ref/WeakReference.html
Zasada: weak reference
jest związana z odśmiecaniem. Zwykle obiekt posiadający jeden lub więcej reference
nie będzie kwalifikował się do odśmiecania.
Powyższa zasada nie ma zastosowania, gdy jest weak reference
. Jeśli obiekt ma tylko słabe odniesienie do innych obiektów, jest gotowy do odśmiecania.
Spójrzmy na poniższy przykład: Mamy Map
z Obiektami, w których Klucz odnosi się do obiektu.
import java.util.HashMap;
public class Test {
public static void main(String args[]) {
HashMap<Employee, EmployeeVal> aMap = new
HashMap<Employee, EmployeeVal>();
Employee emp = new Employee("Vinoth");
EmployeeVal val = new EmployeeVal("Programmer");
aMap.put(emp, val);
emp = null;
System.gc();
System.out.println("Size of Map" + aMap.size());
}
}
Teraz podczas wykonywania programu, który wykonaliśmy emp = null
. Map
Przytrzymanie klawisza nie ma sensu tutaj, jak to jest null
. W powyższej sytuacji obiekt nie jest odśmiecany.
WeakHashMap
WeakHashMap
to taki, w którym wpisy ( key-to-value mappings
) zostaną usunięte, gdy nie będzie już można ich odzyskać z Map
.
Pokażę powyższy przykład tak samo z WeakHashMap
import java.util.WeakHashMap;
public class Test {
public static void main(String args[]) {
WeakHashMap<Employee, EmployeeVal> aMap =
new WeakHashMap<Employee, EmployeeVal>();
Employee emp = new Employee("Vinoth");
EmployeeVal val = new EmployeeVal("Programmer");
aMap.put(emp, val);
emp = null;
System.gc();
int count = 0;
while (0 != aMap.size()) {
++count;
System.gc();
}
System.out.println("Took " + count
+ " calls to System.gc() to result in weakHashMap size of : "
+ aMap.size());
}
}
Wyjście: zajęło 20 calls to System.gc()
wynik aMap size
: 0.
WeakHashMap
ma tylko słabe odniesienia do kluczy, a nie silne odniesienia jak inne Map
klasy. Są sytuacje, na które musisz uważać, gdy wartość lub klucz jest silnie przywołany, mimo że użyłeś WeakHashMap
. Można tego uniknąć, zawijając obiekt w WeakReference .
import java.lang.ref.WeakReference;
import java.util.HashMap;
public class Test {
public static void main(String args[]) {
HashMap<Employee, EmployeeVal> map =
new HashMap<Employee, EmployeeVal>();
WeakReference<HashMap<Employee, EmployeeVal>> aMap =
new WeakReference<HashMap<Employee, EmployeeVal>>(
map);
map = null;
while (null != aMap.get()) {
aMap.get().put(new Employee("Vinoth"),
new EmployeeVal("Programmer"));
System.out.println("Size of aMap " + aMap.get().size());
System.gc();
}
System.out.println("Its garbage collected");
}
}
Miękkie referencje.
Soft Reference
jest nieco silniejszy od tego słabego odniesienia. Miękkie odniesienie pozwala na wyrzucanie elementów bezużytecznych, ale prosi moduł czyszczący o jego usunięcie tylko wtedy, gdy nie ma innej opcji.
Śmieciarka nie zbiera agresywnie obiektów miękko osiągalnych, tak jak ma to miejsce w przypadku słabo osiągalnych - zamiast tego zbiera przedmioty miękko osiągalne tylko wtedy, gdy naprawdę „potrzebuje” pamięci. Miękkie odniesienia to sposób na powiedzenie śmieciarzowi: „Dopóki pamięć nie jest zbyt ciasna, chciałbym utrzymać ten obiekt w pobliżu. Ale jeśli pamięć staje się naprawdę ciasna, idź i zbierz ją, a ja zajmę się z tym." Śmieciarka musi wyczyścić wszystkie miękkie odniesienia, zanim będzie mogła je wyrzucić OutOfMemoryError
.
NullPointerException
in aMap.get().put(...)
.
WeakHashMap
przykład (ponieważ jest to pierwszy, który wykazuje Słabe zachowanie). Spójrz na dokument „WeakHashMap”: "An entry in a WeakHashMap will automatically be removed when its key is no longer in ordinary use. "
Cały sens używania WeakHashMap polega na tym , że nie musisz deklarować / przekazywać WeakReference; WeakHashMap robi to za Ciebie wewnętrznie. docs.oracle.com/javase/7/docs/api/java/util/WeakHashMap.html
WeakHashMap
działania z przykładową aplikacją pokazującą, w jaki sposób wpisy są usuwane dopiero po wykonaniu odśmiecania, zobacz moją odpowiedź na pytanie, czy WeakHashMap ciągle rośnie, czy też usuwa klucze od śmieci? .
Jedyną prawdziwą różnicą między miękkim odniesieniem a słabym odniesieniem jest to
Garbage Collector używa algorytmów, aby zdecydować, czy odzyskać miękko osiągalny obiekt, ale zawsze odzyskuje słabo osiągalny obiekt.
SoftReference
jest przeznaczony do pamięci podręcznych. Kiedy okaże się, że WeakReference
odwołuje się do obiektu nieosiągalnego w inny sposób, zostanie natychmiast wyczyszczony. SoftReference
może pozostać tak jak jest. Zazwyczaj istnieje pewien algorytm związany z ilością wolnej pamięci i czasem ostatnio używanym do ustalenia, czy należy ją wyczyścić. Obecny algorytm firmy Sun polega na usunięciu odwołania, jeśli nie zostało użyte przez tyle sekund, ile w sterty Java jest wolnych megabajtów (konfigurowalne, HotSpot serwera sprawdza maksymalną możliwą stertę ustawioną przez -Xmx
). SoftReference
s zostanie wyczyszczony przed OutOfMemoryError
rzuceniem, chyba że jest osiągalny inaczej.
java.lang
. Takie nadużycie synonimów nie przynosi pożytku.
Ten artykuł może być bardzo pomocny w zrozumieniu silnych, miękkich, słabych i fantomowych odniesień.
Aby dać ci streszczenie,
Jeśli masz tylko słabe odniesienia do obiektu (bez silnych odniesień), obiekt zostanie odzyskany przez GC w następnym cyklu GC.
Jeśli masz tylko miękkie odniesienia do obiektu (bez silnych odniesień), obiekt zostanie odzyskany przez GC tylko wtedy, gdy w JVM zabraknie pamięci.
Możesz więc powiedzieć, że silne referencje mają najwyższą moc (nigdy nie mogą być zebrane przez GC)
Miękkie odniesienia są potężniejsze niż słabe odniesienia (ponieważ mogą uciec cyklowi GC, dopóki w maszynie JVM zabraknie pamięci)
Słabe referencje są nawet mniej skuteczne niż miękkie (ponieważ nie mogą wykasować żadnego cyklu GC i zostaną odzyskane, jeśli obiekt nie ma innych silnych referencji).
Restauracja Analogia
Teraz, jeśli jesteś silnym klientem (analogicznie do mocnego odniesienia), to nawet jeśli nowy klient przyjdzie do restauracji lub coś takiego się wydarzy, nigdy nie opuścisz stołu (obszar pamięci na stosie). Kelner nie ma prawa powiedzieć ci (ani nawet poprosić) o opuszczenie restauracji.
Jeśli jesteś miękkim klientem (analogicznie do miękkiego odniesienia), to jeśli nowy klient przyjdzie do restauracji, kelner nie poprosi cię o opuszczenie stolika, chyba że nie pozostanie już inny pusty stolik, aby pomieścić nowego klienta. (Innymi słowy, kelner poprosi cię o opuszczenie stołu tylko wtedy, gdy wejdzie nowy klient i nie będzie już innego stołu dla tego nowego klienta)
Jeśli jesteś słabym klientem (analogicznie do słabej referencji), to kelner, z własnej woli, może (w dowolnym momencie) poprosić cię o opuszczenie restauracji: P
Zgodnie z dokumentem luźne WeakReferences muszą zostać usunięte przez działający GC.
Zgodnie z dokumentem luźne SoftRefereferencje muszą zostać wyczyszczone przed wyrzuceniem OOM.
To jedyna prawdziwa różnica. Cała reszta nie jest częścią umowy. (Zakładam, że najnowsze dokumenty są umowne.)
Przydatne są SoftReferences. Pamięci wrażliwe na pamięć używają SoftReferences, a nie WeakReferences.
weak_ref.get()
. Kiedy się null
dowiesz, dowiesz się, że między tym czasem trwała GC.
Jeśli chodzi o nieprawidłowe użycie WeakReference, lista jest nieograniczona:
kiepski włamanie do implementacji miękkiego odwołania o priorytecie 2, tak że nie musisz go pisać, ale to nie działa zgodnie z oczekiwaniami, ponieważ pamięć podręczna byłaby czyszczona przy każdym uruchomieniu GC, nawet gdy jest wolna pamięć. Zobacz https://stackoverflow.com/a/3243242/632951, aby zapoznać się ze szczegółami. (Poza tym, co jeśli potrzebujesz więcej niż 2 poziomów priorytetu pamięci podręcznej? Wciąż potrzebujesz do tego prawdziwej biblioteki).
kiepski włamanie do powiązania danych z obiektem istniejącej klasy, ale powoduje przeciek pamięci (OutOfMemoryError), gdy twoja GC postanawia zrobić sobie przerwę po utworzeniu twoich słabych preferencji. Poza tym jest to brzydkie: lepszym rozwiązaniem jest użycie krotek.
kiepski hack do kojarzenia danych z obiektem istniejącej klasy, gdzie klasa ma odwagę, by stać się nieklasowalnym, i jest używana w istniejącym kodzie funkcji, który musisz wywołać. W takim przypadku właściwym rozwiązaniem jest albo edycja klasy i uczynienie jej podklasą, albo edycja funkcji i sprawienie, by przyjmowała interfejs zamiast klasy, lub skorzystała z funkcji alternatywnej.
equals()
jest po prostu tożsamość obiektu? Miękkie odniesienia wydają się marnotrawstwem, ponieważ gdy kluczowy obiekt nie będzie już osiągalny, nikt już nie będzie przeglądał tego mapowania.
Sześć typów stanów osiągalności obiektów w Javie:
Aby uzyskać więcej informacji: https://www.artima.com/insidejvm/ed2/gc16.html «zwiń
Należy zdawać sobie sprawę z tego, że słabo referencyjny obiekt zostanie zebrany tylko wtedy, gdy będzie miał TYLKO słabe referencje. Jeśli ma tyle silnych odniesień, nie zostanie zebrane bez względu na liczbę słabych odniesień.
Aby nadać aspektowi użycia pamięci w działaniu, przeprowadziłem eksperyment z odniesieniami Strong, Soft, Weak & Phantom pod dużym obciążeniem ciężkimi przedmiotami, zachowując je do końca programu. Następnie monitorowano użycie sterty i zachowanie GC . Dane te mogą się różnić w zależności od przypadku, ale z pewnością zapewniają wysoki poziom zrozumienia. Poniżej znajdują się ustalenia.
Zachowanie stosu i GC pod dużym obciążeniem
Możesz uzyskać więcej szczegółowych wykresów, statystyk, obserwacji dla tego eksperymentu tutaj .
WeakReference : obiekty, do których odniesienia są słabo przywoływane, są gromadzone w każdym cyklu GC (mniejszym lub pełnym).
SoftReference : kiedy gromadzone są obiekty, do których odwołuje się tylko miękkie odniesienie, zależy od:
-XX: SoftRefLRUPolicyMSPerMB = Flaga N (wartość domyślna to 1000, czyli 1 sekunda)
Ilość wolnej pamięci w stercie.
Przykład:
Następnie obiekt, do którego odwołuje się tylko SoftReference, zostanie zebrany, jeśli ostatni raz, gdy był dostępny, jest dłuższy niż 10 sekund.