Java: różnica między silnym / miękkim / słabym / fantomowym odniesieniem


179

Przeczytałem ten artykuł na ten temat, ale tak naprawdę go nie rozumiem. Proszę o kilka porad wraz z przykładami przy opisywaniu pojęć.



4
Przeczytałem ten dokument, nie pomaga mi to w wyobrażeniu sobie różnicy. (może dlatego, że jest to trudny do odczytania dokument)

14
Jeśli przeczytałeś ten artykuł i nadal nie rozumiesz, czy masz na jego temat konkretne pytania? Trudno jest odpowiedzieć na „proszę wyjaśnij mi Foo”, „oto co to znaczy”, „nie rozumiem” bez określenia, których części nie dostaniesz.
yshavit


@LouisWasserman Górny link nie jest już ważny.
Mehraj Malik

Odpowiedzi:


142

Java udostępnia dwa różne typy / klasy obiektów referencyjnych : mocne i słabe . Słabe obiekty odniesienia można dalej podzielić na miękkie i pozorne .

  • Silny
  • Słaby
    • miękki
    • Fantom

Przejdźmy punkt po punkcie.

Silny obiekt referencyjny

StringBuilder builder = new StringBuilder();

Jest to domyślny typ / klasa obiektu odniesienia, jeśli nie określono inaczej: builderjest silnym obiektem odniesienia. Ten rodzaj odwołania powoduje, że obiekt, do którego istnieje odwołanie, nie kwalifikuje się do GC. Oznacza to, że za każdym razem, gdy odwołuje się do obiektu łańcuch silnych obiektów referencyjnych , nie można go usunąć.

Słaby obiekt odniesienia

WeakReference<StringBuilder> weakBuilder = new WeakReference<StringBuilder>(builder);

Słabe obiekty referencyjne nie są domyślnym typem / klasą obiektu referencyjnego i aby ich użyć, należy je wyraźnie określić, jak w powyższym przykładzie. Ten rodzaj odniesienia sprawia, że ​​obiekt odniesienia kwalifikuje się do GC. Oznacza to, że w przypadku, gdy jedynym odniesieniem osiągalnym dla StringBuilderobiektu w pamięci jest w rzeczywistości słabe odniesienie, wówczas GC może zebrać StringBuilderobiekt bezużyteczny . Gdy obiekt w pamięci jest osiągalny tylko przez słabe obiekty referencyjne, automatycznie kwalifikuje się do GC.

Poziomy słabości

Można wymienić dwa różne poziomy słabości: miękki i fantomowy .

Miękkie obiekt odniesienia jest zasadniczo słabe odniesienia Obiekt, który pozostaje w pamięci nieco więcej: Zwykle jest on odporny na cykl GC aż do zaniku pamięci jest dostępny i nie ma ryzyka OutOfMemoryError(w tym przypadku, może być usunięty).

Z drugiej strony, fantomowy obiekt referencyjny jest przydatny tylko po to, aby wiedzieć dokładnie, kiedy obiekt został skutecznie usunięty z pamięci: zwykle są one używane do naprawiania dziwnego zachowania finalize () odrodzenia / wskrzeszenia , ponieważ w rzeczywistości nie zwracają samego obiektu, ale tylko pomagać w śledzeniu obecności ich pamięci .

Słabe obiekty referencyjne są idealne do implementacji modułów pamięci podręcznej. W rzeczywistości rodzaj automatycznej eksmisji można zaimplementować, umożliwiając GC czyszczenie obszarów pamięci, gdy obiekty / wartości nie są już osiągalne przez silny łańcuch odwołań. Przykładem jest WeakHashMap zachowujący słabe klucze.


76

Słabe odniesienie:

Krótko mówiąc, słabe odniesienie to odniesienie, które nie jest wystarczająco silne, aby zmusić obiekt do pozostania w pamięci. Słabe referencje pozwalają wykorzystać zdolność garbage collectora do określenia osiągalności dla Ciebie, więc nie musisz tego robić samodzielnie.

Miękkie odniesienie:

Miękkie odniesienie jest dokładnie takie samo, jak słabe odniesienie, z tą różnicą, że rzadziej wyrzuca obiekt, do którego się odnosi. Obiekt, który jest tylko słabo osiągalny (najsilniejsze odniesienia do niego to WeakReferences) zostanie odrzucony w następnym cyklu usuwania elementów bezużytecznych, ale obiekt, który jest łatwo osiągalny, na ogół pozostanie w pobliżu przez jakiś czas.

Odniesienie do fantomu:

Odniesienie do fantomu jest zupełnie inne niż SoftReference lub WeakReference. Jego uchwyt na obiekcie jest tak słaby, że nie możesz nawet go pobrać - jego metoda get () zawsze zwraca wartość null. Jedynym zastosowaniem takiego odniesienia jest śledzenie, kiedy zostanie umieszczone w kolejce ReferenceQueue, ponieważ w tym momencie wiesz, że obiekt, na który wskazywał, jest martwy.

Ten tekst został pobrany z: https://weblogs.java.net/blog/2006/05/04/understanding-weak-references


1
Chociaż wszystko w tej odpowiedzi wygląda na poprawne, wydaje mi się również, że na połączonej stronie internetowej może występować błąd. Javadoc pakietu java.lang.ref a dla PhantomReference sugerują, że przedmiot nie jest zbierane śmieci dopóki nie jest już „fantom osiągalny”, co oznacza, że (w przeciwieństwie do SoftReference) ą PhantomReference należy rozkolejkowywana przed obiektem, który odnosi się do puszki być zbierającym elementy bezużyteczne ... a ich kolejkowanie nie oznacza, że ​​skojarzona pamięć została zwolniona.
Theodore Murdock

2
Dla przypomnienia, wolałbym raczej żyć w świecie, w którym ten wpis na blogu jest poprawny.
Theodore Murdock

1
@TheodoreMurdock Plik javadoc jest poprawny. Odwołanie do fantomu w ogóle nie utrudnia czyszczenia pamięci. Po umieszczeniu obiektu w kolejce nie może zostać zapisany nawet przez finalizator, ponieważ finalizatory już działały. Jest martwy, ale jeszcze nie zniknął.
Leliel

@Leliel Właściwie odniesienie fantom robi w rzeczywistości utrudniają zbierania śmieci po jego skolejkowany ... Uświadomiłem sobie niedawno, gdy błąd spowodowany wątek oczyszczania, aby wyjść wcześnie. Istnienie odwołań fantomowych było wystarczające, aby zapewnić, że każdy obiekt, do którego odwołuje się fantom, został zachowany w moim zrzucie sterty, niedostępny do zebrania ... jeśli nie uda się przetworzyć kolejki lub nie zakwalifikujesz odwołania do fantomu kwalifikującego się do gc podczas przetwarzania kolejki ( i nie czyść () odwołania do fantomu), wtedy przeciek pamięci będzie zawierał zarówno odwołanie do fantomu, jak i obiekt, do którego się odwołuje.
Theodore Murdock

25

Prosta różnica między SoftReferencei WeakReferencejest dostarczana przez programistę Android .

Różnica między a SoftReferencei a WeakReferenceto moment, w którym zapada decyzja o wyczyszczeniu i umieszczeniu odniesienia w kolejce:

  • SoftReferencePowinny być wyczyszczone i skolejkowany tak późno jak to możliwe, czyli w przypadku VM jest w niebezpieczeństwie wyczerpaniu pamięci.

  • A WeakReferencemożna wyczyścić i umieścić w kolejce, gdy tylko wiadomo, że zawiera słabe odniesienia.


16

Trzy terminy, których użyłeś, są głównie związane z uprawnieniem obiektu do pobierania elementów bezużytecznych.

Słabe odniesienie : Jest to odniesienie, które nie jest wystarczająco silne, aby zmusić obiekt do pozostania w pamięci. To kaprysy garbage collectora, żeby zebrać ten obiekt do wyrzucenia śmieci. Nie możesz zmusić tego GC, żeby go nie odebrał .

Miękkie odniesienie : To mniej więcej to samo, co słabe odniesienie. Ale można powiedzieć, że trzyma obiekt nieco mocniej niż słabe odniesienie z czyszczenia pamięci.

Jeśli moduł wyrzucania elementów bezużytecznych zbierze słabe odniesienie w pierwszym cyklu życia, zbierze miękkie odniesienie w następnym cyklu usuwania elementów bezużytecznych.

Silne odniesienie : Jest to przeciwieństwo dwóch powyższych rodzajów odniesień. Mniej lubią zbierać śmieci (przeważnie nigdy nie są zbierane).

Możesz skorzystać z następującego łącza, aby uzyskać więcej informacji:

http://docs.oracle.com/javase/1.4.2/docs/api/java/lang/ref/Reference.html


3
Myślę, że jest to błędne - „Jeśli zbieracze elementów bezużytecznych zbierają słabe odniesienie w pierwszym cyklu życia, to w następnym cyklu zbierania elementów bezużytecznych będą zbierać miękkie odniesienia”. Niekoniecznie tak jest, jak możesz być tak pewny, że wystąpią one w kolejnym przebiegu GC? GC może umożliwić życie obiektom, do których istnieją odniesienia, nawet w drugim i trzecim przebiegu. Nie ma do tego dokumentacji, jeśli jest, podaj link określający.
Saurabh Patil

2
Twoja odpowiedź jest również trochę niejasna, spójrz na to zdanie: „To mniej więcej to samo, co słabe odniesienie. Ale można powiedzieć, że trzyma obiekt nieco mocniej niż słabe odniesienie z czyszczenia pamięci ”. - wyraźnie pyta o różnicę, a nie podobieństwa, wszystkie te słowa dodają do tematu więcej zamieszania niż jasności.
Saurabh Patil

@SaurabhPatil - Brakuje Twojego komentarza. Oto odpowiedzi. 1. „wyraźnie pyta o różnicę, a nie o podobieństwa” - odwołaj się do opisu pytania (a nie „tylko” w tytule) „Proszę o radę i jakiś przykład do opisania”. 2. „Ale można powiedzieć, że trzyma przedmiot nieco bardziej…” Myślę, że SOF daje możliwość głosowania przeciwnego i udzielania nowych odpowiedzi.
Sabya

14

Ten artykuł może być bardzo pomocny w zrozumieniu silnych, miękkich, słabych i fantomowych odniesień.


Aby dać ci podsumowanie,

Jeśli masz silne odwołanie do obiektu, obiekt nigdy nie może zostać zebrany / odzyskany przez GC (Garbage Collector).

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 odwołania do obiektu (bez silnych odniesień), obiekt zostanie odzyskany przez GC tylko wtedy, gdy zabraknie pamięci JVM.

Tworzymy odniesienia pozorne do obiektu, aby śledzić, kiedy obiekt zostanie umieszczony w kolejce do ReferenceQueue. Gdy już wiesz, że możesz przeprowadzić drobnoziarnistą finalizację. (To uchroniłoby cię przed przypadkowym wskrzeszeniem obiektu, ponieważ widmo-odniesienie nie daje ci odsyłacza). Proponuję przeczytać ten artykuł, aby uzyskać szczegółowe informacje na ten temat.


Możesz więc powiedzieć, że silne odniesienia mają najwyższą moc (nigdy nie mogą być zebrane przez GC)

Miękkie odwołania są potężniejsze niż słabe odwołania (ponieważ mogą uciec przed cyklem GC, dopóki JVM nie zabraknie pamięci)

Słabe odniesienia są nawet mniej wydajne niż odniesienia miękkie (ponieważ nie mogą uciec od żadnego cyklu GC i zostaną odzyskane, jeśli obiekt nie ma innego silnego odniesienia).


Restauracja Analogia

  • Kelner - GC
  • Ty - Obiekt w kupie
  • Powierzchnia / przestrzeń restauracji - Przestrzeń na sterty
  • Nowy klient - nowy obiekt, który chce stołować się w restauracji

Teraz, jeśli jesteś silnym klientem (analogicznie do silnego odniesienia), to nawet jeśli do restauracji wejdzie nowy klient lub cokolwiek się dzieje, nigdy nie opuścisz swojego stołu (obszar pamięci na stercie). Kelner nie ma prawa mówić (ani nawet prosić) o opuszczenie restauracji.

Jeśli jesteś klientem miękkim (analogicznie do miękkiego odniesienia), to jeśli do restauracji wejdzie nowy klient, kelner nie poprosi Cię o opuszczenie stolika, chyba że nie ma już innego pustego stolika, który mógłby pomieścić nowego klienta. (Innymi słowy, kelner poprosi Cię o opuszczenie stołu tylko wtedy, gdy pojawi się nowy klient i nie ma już innego stolika dla tego nowego klienta)

Jeśli jesteś słabym klientem (analogicznie do słabego odniesienia), to kelner może (w dowolnym momencie) poprosić Cię o opuszczenie restauracji: P


10

4 stopnie odniesienia - Strong, Weak, Soft, Phantom

Strong - jest rodzajem odwołania, które powoduje, że obiekt, do którego istnieje odwołanie, nie kwalifikuje się do GC. klasy budowniczych. np. - StringBuilder

Słaby - to odniesienie, które kwalifikuje się do GC.

Soft - to rodzaj odniesienia, którego obiekt kwalifikuje się do GC, dopóki pamięć nie będzie dostępna. Najlepsze do pamięci podręcznej obrazów. Będzie je przechowywać, dopóki pamięć nie będzie dostępna.

Fantom - to rodzaj odniesienia, którego obiekt bezpośrednio kwalifikuje się do GC. Używane tylko, aby wiedzieć, kiedy obiekt jest usuwany z pamięci.

używa:

  1. Umożliwia określenie, kiedy obiekt jest dokładnie usuwany z pamięci.

  2. gdy finalize()metoda jest przeciążona, GC może nie nastąpić w odpowiednim czasie dla obiektów kwalifikujących się do GC z dwóch klas. Tak więc odniesienie do fantomu kwalifikuje je wcześniej do GC finalize(), dlatego możesz uzyskać OutOfMemoryErrors nawet wtedy, gdy większość sterty to śmieci.

Słabe referencje są idealne do implementacji modułów pamięci podręcznej.


10

Silne odniesienia

Oto Twoje zwykłe odniesienia do obiektów, które codziennie kodujemy:

Employee emp = new Employee();

Zmienna „emp” zawiera silne odwołanie do obiektu pracownika, a obiekty, do których można dotrzeć za pośrednictwem dowolnego łańcucha silnych odniesień, nie kwalifikują się do czyszczenia pamięci. Zwykle tego chcesz, ale nie zawsze. Teraz przypuśćmy, że pobieramy wielu pracowników z bazy danych w kolekcji lub mapie i musimy regularnie wykonywać na nich dużo przetwarzania, więc aby zachować wydajność, będziemy przechowywać ich w pamięci podręcznej.

O ile jest to dobre, ale teraz potrzebujemy różnych danych i nie potrzebujemy tych obiektów pracowników, a do nich nie można się odwoływać z dowolnego miejsca poza pamięcią podręczną. Co powoduje wyciek pamięci, ponieważ te obiekty nie są używane, ale nadal nie kwalifikują się do czyszczenia pamięci i nie możemy usunąć tych obiektów z pamięci podręcznej, ponieważ nie mamy do nich odniesienia? Więc tutaj albo musimy ręcznie opróżnić całą pamięć podręczną, co jest żmudne, albo możemy użyć innych rodzajów referencji, np. Słabe referencje.

Słabe odniesienia

Słabe odniesienie nie przypina obiektu do pamięci i zostanie poddane GC w następnym cyklu GC, jeśli nie zostanie przywołane z innych odniesień. Możemy użyć klasy WeakReference, która jest dostarczana przez Javę, aby stworzyć powyższy rodzaj pamięci podręcznych, które nie będą przechowywać obiektów, do których nie istnieją odwołania z innych źródeł.

WeakReference<Cache> cache = new WeakReference<Cache>(data);

Aby uzyskać dostęp do danych, musisz wywołać cache.get (). To wywołanie get może zwrócić wartość null, jeśli słabe odniesienie zostało zebrane w pamięci: musisz sprawdzić zwracaną wartość, aby uniknąć NPE. Java udostępnia kolekcje, które używają słabych odniesień, np. Klasa WeakHashMap przechowuje klucze (nie wartości) jako słabe odwołania. Jeśli klucz jest oznaczony GC, wartość zostanie również automatycznie usunięta z mapy.

Ponieważ słabe odwołania są również obiektami, potrzebujemy sposobu, aby je wyczyścić (nie są już przydatne, gdy obiekt, do którego się odnosili, został poddany GC). Jeśli przekażesz ReferenceQueue do konstruktora dla słabego odwołania, moduł wyrzucania elementów bezużytecznych dołączy to słabe odwołanie do ReferenceQueue, zanim zostaną sfinalizowane lub poddane GC. Możesz okresowo przetwarzać tę kolejkę i radzić sobie z martwymi odwołaniami.

Miękkie odniesienia

SoftReference jest podobny do WeakReference, ale jest mniej prawdopodobne, że zostanie wyrzucony jako śmieci. Miękkie odwołania są czyszczone według uznania modułu odśmiecania pamięci w odpowiedzi na zapotrzebowanie na pamięć. Maszyna wirtualna gwarantuje, że wszystkie miękkie odwołania do miękko dostępnych obiektów zostaną wyczyszczone, zanim wyrzuci ona błąd OutOfMemoryError.

Odniesienia fantomowe

Odwołania fantomowe są najsłabszymi ze wszystkich typów odwołań, wywołanie ich wywołania zawsze zwróci wartość null. Do obiektu odwołuje się fantom po jego sfinalizowaniu, ale przed odzyskaniem przydzielonej mu pamięci, w przeciwieństwie do słabych referencji, które są umieszczane w kolejce przed sfinalizowaniem lub referencje fantomowe GC są rzadko używane.

Jak więc są przydatne? Kiedy konstruujesz odniesienie do fantomu, musisz zawsze przekazać ReferenceQueue. Oznacza to, że możesz użyć odwołania pozornego, aby zobaczyć, kiedy obiekt jest oznaczony metodą GC.

Hej, więc jeśli słabe referencje są kolejkowane, gdy są uważane za sfinalizowane, ale jeszcze nie GC, moglibyśmy utworzyć nowe silne odniesienie do obiektu w bloku finalizatora i uniemożliwić GC obiektowi. Tak, możesz, ale prawdopodobnie nie powinieneś tego robić. Aby sprawdzić ten przypadek, cykl GC nastąpi co najmniej dwa razy dla każdego obiektu, chyba że obiekt ten jest osiągalny tylko przez odniesienie fantomowe. Dlatego możesz zabraknąć stosu, nawet jeśli twoja pamięć zawiera mnóstwo śmieci. Mogą temu zapobiec odniesienia fantomowe.

Więcej na ten temat przeczytasz w moim artykule Typy referencji w Javie (Strong, Soft, Weak, Phantom) .


napisałeś, że słabe refrenes zostaną poddane GC w następnym cyklu, jeśli nie zostaną odwołane od innych refrenów ... ale czy nie powinno się zdarzyć tego samego z silnymi refrenami? jeśli nie można uzyskać dostępu do stron refren, to zostaje wyczyszczone ... a jeśli tak, to gdzie znowu jest różnica ...? #confused
filemonczyk

1
Jeśli obiekt jest wywoływany z, powiedzmy, s1 (silny) i s2 (silny), obiekt nie będzie kwalifikował się do czyszczenia pamięci, dopóki zarówno s1, jak i s2 nie zostaną dereferencjonowane, ale jeśli obiekt jest odwoływany z s1 (słaby) i s2 ( strong) to obiekt będzie kwalifikował się do wyrzucania elementów bezużytecznych w następnym cyklu GC, gdy zostanie wyodrębniony tylko z s2, ponieważ s1 jest słabym odniesieniem i jeśli obiekt nie ma żadnego innego odniesienia oprócz słabego, kwalifikuje się do GC
Naresh Joshi
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.