Garbage Collector Javy 4/5

Zmiany stanu osiągalności
Jak wspomniano wcześniej, obiekty referencyjne są po to by móc trzymać referencję do obiektów które garbage collector może zwolnić. Innymi słowy garbage collector może zmienić stan osiągalności każdego obiektu który nie jest silnie osiągalny. Ponieważ często jest ważne aby śledzić zmiany stanu osiągalności powodowane przez garbage collector, kiedy trzymasz miękkie, słabe lub fantomowe referencje, możesz nakazać powiadamiać o takich zmianach. Aby zarejestrować zainteresowanie zmianami dostępności, kojarzy się obiekty referencyjne z kolejkami referencyjnymi. Kolejka referencyjna jest instancją klasy java.lang.ref.ReferenceQueue do której garbage collector dołącza obiekty referencyjne pociągając zmiany stanu osiągalności. Poprzez ustanowienie i monitorowanie kolejki odniesienia, możesz zostać powiadomiony o interesujących zmianach stanu dostępności wykonywanych asynchronicznie przez garbage collector.

Aby powiązać obiekt referencyjny z kolejką referencyjną należy po prostu podać referencję do kolejki referencji jako parametr konstruktora kiedy tworzymy obiekt referencyjny. Obiekt referencyjny tak utworzony oprócz trzymania referencji do referenta będzie trzymał referencję do kolejki referencji. Kiedy garbage collector sprawi istotne zmiany w stanie osiągalności referenta, doda obiekt referencyjny do związanej z nim kolejki odniesienia. Na przykład kiedy zostanie utworzony obiekt WeakReference pokazany na rysunku 9-5, dwie referencje zostaną przekazane do konstruktora: referencja do obiektu Fox i referencja do obiektu ReferenceQueue. Kiedy garbage collector zdecyduje się zabrać słabo osiągalny obiekt Fox, wyczyści obiekt WeakReference i albo w tym albo późniejszym czasie dołączy obiekt WeakReference do jego kolejki referencji.


Rysunek 9-5. Obiekt referencyjny związany z kolejką referencyjną.
Aby dodać obiekt referencyjny na koniec związanej z nim kolejki, garbage collector wywołuje enqueue() na obiekcie referencyjnym. Metoda enqueue() która jest zdefiniowana w superklasie Reference dołącza referencyjny obiekt do kolejki referencyjnej jedynie jeśli obiekt był związany z kolejką kiedy był tworzony i wołane jest na obiekcie jedynie pierwsze enqueue(). Programy mogą monitorować kolejkę referencyjną na dwa sposoby: albo przez odpytywanie metodą poll() lub przez blokowanie metodą remove(). Jeśli obiekt referencyjny czeka w kolejce kiedy wołana jest albo poll() albo remove()na obiekcie w kolejce, metoda usunie obiekt z kolejki referencyjnej i zwróci go. Jeśli nie ma obiektów referencyjnych czekających w kolejce, poll() natychmiast zwróci null,ale remove() będzie blokowało dotąd aż następny obiekt referencyjny dostanie się do kolejki. Gdy tylko obiekt referencyjny pojawi się w kolejce, remove() usunie i zwróci go.
Garbage collector kolejkuje miękkie, słabe i fantomowe obiekty referencyjne w różnych sytuacjach aby wskazać trzy różne rodzaje zmian stanu osiągalności. Znaczenia sześciu stanów osiągalności i okoliczności w jakich zmiany stanu się zdarzają są następujące:
*silnie osiągalny – Obiekt może być osiągnięty z korzeni bez przejścia przez obiekt referencyjny. Obiekt zaczyna swoje życie w silnie osiągalnym stanie i pozostaje silnie osiągalny tak długo jak jest osiągalny z węzłów root lub innego silnie osiągalnego obiektu. Garbage collector nie będzie próbował odzyskać pamięci zajmowanej przez silnie osiągalny obiekt.
*miękko osiągalny – Obiekt nie jest silnie osiągalny ale może być osiągnięty z korzeni przez jeden lub więcej obiektów miękkiej referencji. Garbage collector może odzyskać pamięć zajmowaną przez miękko osiągalny obiekt. Jeśli to zrobi, usuwa wszystkie miękkie referencje do tego miękko osiągalnego obiektu. Kiedy garbage collector wyczyści obiekt miękkiej referencji który jest związany z kolejką referencji, doda do kolejki ten obiekt referencyjny.
*słabo osiągalny – Obiekt nie jest ani silnie ani miękko osiągalny ale może być osiągnięty od korzeni przez jeden lub więcej obiektów słabej referencji. Garbage collector musi odzyskać pamięć zajmowaną przez obiekt słabo osiągalny. Gdy to uczyni, czyści wszystkie słabe referencje do tego słabo osiągalnego obiektu. Kiedy garbage collector czyści obiekt słabej referencji który jest związany z kolejką referencji, dodaje do kolejki ten obiekt.
*wskrzeszalny – Obiekt nie jest ani silnie ani miękko ani słabo dostępny ale może być nadal wskrzeszony do tych stanów przez wykonanie finalizatora.
*fantomowo dostępny – Obiekt nie jest silnie,miękko ani słabo osiągalny, zostało ustalone że nie może być wskrzeszony przez finalizator (jeśli deklaruje metodę finalize() wtedy jego finalizator będzie uruchomiony) i może być osiągalny od korzeni przez jeden lub więcej obiektów fantomowej referencji. Tak szybko jak obiekt do którego jest odwołanie przez fantomową referencję staje się fantomowo osiągalny, garbage kolektor doda go do kolejki. Garbage collector nigdy nie czyści fantomowej referencji. Wszystkie fantomowe referencje muszą być jawnie czyszczone przez program.
*nieosiągalny – Obiekt nie jest silnie,miękko,słabo ani fantomowo osiągalny ani nie jest wskrzeszalny. Nieosiągalne obiekty są gotowe do regeneracji.
należy pamiętać że podczas gdy garbage collector kolejkuje obiekty miękkiej i słabej referencji kiedy ich obiekty odniesienia opuszczają związany z nimi stan osiągalności, kolejkuje fantomową referencję kiedy obiekt odniesienia wchodzi w odpowiedni stan. Możesz również zobaczyć tą różnicę w tym że garbage collector czyści obiekty miękkiej i słabej referencji zanim zakolejkuje je ale nie obiekty fantomowej referencji. Tak więc garbage collector kolejkuje obiekty miękkiej referencji aby oznaczać że ich obiekt odniesienia właśnie opuścił miękko osiągalny stan. Podobnie garbage collector kolejkuje obiekty słabej referencji aby oznaczyć że ich obiekt odniesienia właśnie opuścił słabo osiągalny stan. Ale kolejkuje obiekty fantomowej referencji aby oznaczyć że ich obiekt odniesienia wchodzi w stan fantomowej osiągalności. Obiekt fantomowo osiągalny będą fantomowo osiągalne aż ich obiekty odniesienia zostaną jawnie wyczyszczone przez program.

Cache, kanonizowane mapowanie i przedśmiertne czyszczenie

Garbage collector traktuje miękkie, słabe i fantomowe obiekty różnie ponieważ każdy ma na celu zapewnienie różnego rodzaju usług do programu. Miękka referencja umożliwia tworzenie cache w pamięci które są wrażliwe na ogólną potrzebę pamięci programu. Słabe referencje pozwalają na stworzenie kanonizowalnych map takich jak tablica hash których klucze i wartości będą usunięte z mapy jeśli program nie będzie się do nich odwoływał. Fantomowa referencja pozwala na wprowadzenie bardziej elastycznej polityki czyszczenia przedśmiertnego niż jest możliwa za pomocą finalizatorów.
Aby użyć obiekt do którego się odwołujemy za pomocą miękkiej lub słabej referencji, wywołaj get() na tym obiekcie. Jeśli referencja nie została wyczyszczona, otrzymasz silną referencję do obiektu odniesienia. którą można następnie użyć w zwykły sposób. Jeśli referencja jest wyczyszczona dostaniesz null. Jeśli wywołasz get() na obiekcie fantomowej referencji zawsze otrzymasz null nawet jeśli obiekt referencji nie został jeszcze czyszczony. Ponieważ stan fantomowej osiągalności jest jedynie osiągnięty po przejściu przez stan wskrzeszalny, obiekt fantomowej referencji nie dostarcza sposobu dostępu do jego obiektu odniesienia. Wywołując get() na obiekcie fantomowej referencji zawsze dostaniemy null nawet jeśli fantomowa referencja jeszcze nie była czyszczona, ponieważ jeśli byśmy dostali silną referencję do fantomowo osiągalnego obiektu w efekcie wskrzesilibyśmy by ten obiekt. Tak więc gdy obiekt osiągnie fantomową osiągalność nie może być wskrzeszony.
Implementacja wirtualnej maszyny wymaga aby czyścić miękką referencję przed rzuceniem OutOfMemoryError, ale może decydować kiedy i czy je czyści. Implementacja zachęca jednak aby czyścić miękką referencję jedynie kiedy popyt na pamięć przewyższa podaż, aby czyścić starszą miękką referencję przed nową i czyścić miękką referencję która nie była użyta ostatnio przed miękką referencją która była użyta ostatnio.
Miękkie referencje pozwalają na cache w pamięci danych, które można pobrać wolniej z zewnętrznego źródła, takiego jak plik, bazy danych lub z sieci. Tak długo jak wirtualna maszyna ma wystarczająco dużo pamięci aby dopasować miękko referencyjne dane na stercie razem ze wszystkimi silnie referencyjnymi danymi, miękka referencja jest w ogólności wystarczająco silna do trzymania miękko referencyjnych danych na stercie. Jeśli pamięć staje się dobrem rzadkim, garbage collector może decydować aby wyczyścić miękką referencję i odzyskać miejsce zajmowane przez miękkoreferencyjne dane. Następnym razem kiedy program będzie potrzebował użyć tych danych, będzie musiał załadować je ponownie z zewnętrznego źródła. W międzyczasie wirtualna maszyna ma więcej miejsca aby pomieścić silną (i inną miękką) pamięć referencji potrzebną przez program.
Słabe referencje są podobne do miękkich referencji z wyjątkiem, że podczas gdy garbage collector może decydować czy lub nie czyścić miękkich referencji do miękko osiągalnych obiektów, musi czyścić słabe referencje do słabo osiągalnych obiektów tak szybko jak określi że obiekty są słabo osiągalne. Słabe referencje umożliwiają tworzenie kanonicznych mapowań kluczy na wartości. Klasa

java.util.WeakHashMap

używa słabej referencji do dostarczenia takich właśnie kanonicznych mapowań. Możesz dodać parę klucz-wartość do instancji WeakHashMap za pomocą metody put() tak jak do jakiejkolwiek instancji klasy która implementuje

java.util.Map

. Ale wewnątrz WeakHashMap obiekty kluczy są trzymane przez obiekty słabej referencji które są związane z kolejką referencyjną. Jeśli garbage collector stwierdzi że obiekt klucza jest miękko osiągalny, wyczyści i doda do kolejki obiekty słabej referencji które odnoszą się do obiektu klucza. Następnym razem gdy mamy dostęp do WeakHashMap GC odpyta kolejkę referencyjną i wyodrębni wszystkie obiekty słabej referencji które garbage collector tu umieścił. Klasa WeakHashMap następnie usunie ze swojego mapowania parę klucz-wartość dla kluczy których obiekt słabej referencji pokazał się w kolejce. Tak więc jeśli dodasz parę klucz-wartość do WeakHashMap to pozostanie tam tak długo jak program wyraźnie nie usunie go metodą remove() i garbage collector nie określa czy obiekt klucza jest słabo osiągalny.
Widmowa dostępność wskazuje, że obiekt jest gotowy do regeneracji. Gdy garbage collector stwierdzi że obiekt fantomowej referencji jest fantomowo osiągalny, dołącza go do związanej z nim kolejki referencji. (W przeciwieństwie do miękkich i słabych obiektów odniesienia, które ewentualnie mogą być tworzone bez kojarzenia ich z kolejką referencji, nie może być instancji obiektów fantomowej referencji bez przypisywania obiektu do kolejki.) Możesz użyć zdarzenia przybycia fantomowej referencji do kolejki referencji do uruchomienia niektórych działań pod koniec życia obiektu. Ponieważ nie można uzyskać silnej referencji do fantomowo osiągalnego obiektu (metoda

get()

zawsze zwraca

null

), nie będzie można podejmować żadnych działań, które wymagają dostępu do zmiennych instancji. Po zakończeniu akcji przedśmiertnego czyszczenia dla fantomowo osiągalnego obiektu, należy wywołać

clear()

na obiektach fantomowej referencji które odnoszą się do niego. Wywoływanie

clear()

na obiekcie fantomowej referencji jest strzałem miłosierdzia dla jego referenta, jest wysyłaniem referenta z ze stanu fantomowej osiągalności do ostatecznego miejsca spoczynku: nieosiągalności.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *