Garbage Collector Javy 3/5

Finalizacja
W Javie obiekt może posiadać finalizator: metodę którą garbage collector musi uruchomić przed zwolnieniem obiektu. Potencjalne istnienie finalizatorów komplikuje pracę garbage collectora w wirtualnej maszynie Javy.
Aby dodać finalizator do klasy wystarczy po prostu zadeklarować metodę w tej klasie następująco:
// Na CD-ROM w pliku gc/ex2/Example2.java
class Example2 {

    protected void finalize() throws Throwable {
        //...
        super.finalize();
    }
    //...


Garbage collector musi zbadać wszystkie obiekty które nie mają referencji czy mają metodę finalize();
Z powodu finalizatorów garbage collector musi wykonać dodatkowe kroki za każdym razem gdy zwalnia obiekt. Po pierwsze garbage collector musi w pewien sposób wykryć obiekty bez referencji (faza I). Następnie mus zbadać obiekty bez referencji które wykrył czy mają zadeklarowany finalizator. Jeśli ma wystarczająco dużo czasu, może w tym momencie zbierania śmieci sfinalizować wszystkie obiekty bez referencji które mają zadeklarowane finalizatory.
Po wykonaniu wszystkich finalizatorów garbage collector musi jeszcze raz wykryć obiekty bez referencji startując z korzeni (faza II). Ten krok jest potrzebny ponieważ finalizatory mogą “wskrzeszać” obiekty bez referencji i powodować że będą miały referencje. Na koniec garbage collector może zwolnić wszystkie obiekty które znalazł że nie mają referencji w obu fazach I i II.
Aby zredukować czas zwalniania pamięci garbage collector może opcjonalnie wstawiać krok pomiędzy wykryciem obiektów bez referencji które mają finalizatory i uruchomieniem tych finalizatorów. Gdy tylko garbage collector wykona fazę I i znajdzie obiekty bez referencji które muszą być sfinalizowane może uruchomić miniaturowe śledzenie startując nie z od korzeni ale od obiektów czekających na finalizację. Obiekty które są (1) nie osiągalne z węzłów root (te wykryte podczas fazy I) i (2) nie osiągalne przez obiekty czekające na finalizację, nie mogą być wskrzeszone przez żaden finalizator. Te obiekty mogą być zwolnione natychmiast.
Jeżeli obiekt z finalizatorem zostaje bez referencji a jego finalizator jest uruchomiony, garbage collector musi w jakiś sposób zapewnić że nigdy nie uruchomi tego finalizatora ponownie. Jeżeli obiekt jest wskrzeszony przez finalizator swój lub innego obiektu i później został znowu bez referencji, garbage collector musi traktować go jako obiekt który nie ma finalizatora.
Gdy programujesz w Javie musisz pamiętać, że jest garbage collector, który uruchgamia finalizatory na obiektach. Ponieważ nie jest ogólnie możliwe przewidzieć dokładnie kiedy obiekt bez odniesień będzie czyszczony nie jest możliwe przewidzieć kiedy będzie uruchomiony finalizator obiektu. Jak wspomniano w rozdziale 2. “Niezależność od platformy” powinieneś unikać pisania programów których poprawność zależy od finalizowania obiektów w odpowiednim czasie. Na przykład jeśli finalizator obiektu bez referencji zwalnia zasób który jest potrzebny później przez program, zasób nie będzie dostępny dopóki garbage collector nie wywoła finalizatora. Jeżeli program potrzebuje zasobu zanim garbage collector sfinalizuje obiekt bez odniesień, można powiedzieć że ma pecha.

Cykl życiowy i osiągalność obiektów

W wersjach sprzed 1.2 każdy obiekt na stercie był w jednym z trzech stanów z punktu widzenia garbage collectora osiągalny, wskrzeszalny i nieosiągalny. Obiekt jest osiągalny jeżeli garbage collector może “osiągnąć” obiekt śledząc graf referencji obiektów startując od węzłów root. Każdy obiekt zaczyna swoje życie w stanie osiągalny i jest osiągalny tak długo jak program utrzymuje co najmniej jedną osiągalną referencję do obiektu. Jak tylko program zwolni wszystkie referencje do obiektu, staje się on wskrzeszalny.
Obiekt jest w stanie wskrzeszalny jeśli nie jest obecnie osiągalny przez poprzez śledzenie grafu referencji startując od węzłów root ale może być potencjalnie osiągalny później kiedy garbage collector wykona finalizatory. Wszystkie obiekty, nie tylko te mające metodę finalize() przechodzą przez stan wskrzeszalny. Jak wspomniano w poprzedniej części, finalizator obiektu może “wskrzesić” go lub inny wskrzeszalny obiekt czyniąc go znowu osiągalnym. Ponieważ obiekt w stanie wskrzeszalny może być potencjalnie osiągalny, garbage collector nie może zwolnić pamięci zajmowanej przez wskrzeszalne obiekty zanim nie będzie pewności że obiekt nie zostanie przywrócony do życia przez wykonanie finalizatora. Przez wykonanie finalizatorów wskrzeszalnych obiektów które deklarują metodę finalize() garbage collector zmieni stan wszystkich wskrzeszalnych obiektów albo znowu do stanu osiągalny (dla obiektów które zostały wskrzeszone) lub do stanu nieosiągalny.
Stan nieosiągalny oznacza nie tylko że obiekt nie jest już osiągalny ale również że obiekt nie może być osiągalny znowu przez wywołanie finalizatora. Nieosiągalne obiekty nie będą miały już wpływu na działający program. Garbage collector może więc zwolnić pamięć którą zajmują.
W wersji 1.2 trzy stany osiągalności – osiągalny, wskrzeszalny i nieosiągalny – zostały powiększone przez trzy nowe stany: miękko, słabo i fantomowo osiągalny. Ponieważ te trzy nowe stany reprezentują trzy nowe (postępująco słabnące) rodzaje osiągalności, stan znany po prostu jako “osiągalny” w wersji do 1.2 jest zwany “silnie osiągalny” zaczynając od 1.2. Obiekt mający odniesienia bezpośrednio od korzenia takiego jak lokalna zmienna jest silnie osiągalny. Podobnie obiekt mający odniesienia od instancji zmiennej silnie osiągalnego obiektu jest silnie osiągalny.

Reference Objects
Słabsze formy osiągalności dotyczą jednostki która była wprowadzona w wersji 1.2. reference object. Reference object zamyka referencję do innego obiektu zwanego referent. Wszystkie obiekty referencji są instancjami podklas klasy abstrakcyjnej java.lang.ref.Reference. Rodzina klas Reference obejmuje trzy bezpośrednie podklasy SoftReference, WeakReference i PhantomReference.
Obiekt SoftReference hermetyzuje “miękką referencję” do obiektu odniesienia. Obiekt WeakReference hermetyzuje “słabą referencję” do obiektu odniesienia a PhantomReference “fantomową referencję” do obiektu odniesienia. Podstawowa różnica między silną referencją a jej trójka stopniowo słabnącymi kuzynkami – miękką, słabą i fantomową referencją – jest że podczas gdy silna referencja zapobiega przed zebraniem przez garbage collector obiekt odniesienia, miękka, słaba i fantomowa referencja nie.

Rys. 9-3. Rodzina klas Reference
Aby utworzyć miękką, słabą i fantomową referencję wystarczy po prostu podać silną referencję do konstruktora odpowiedniego typu obiektu referencyjnego. Na przykład aby utworzyć miękką referencję to konkretnego obiektu Cow, podajesz do konstruktora nowego obiektu SoftReference silną referencję która odnosi się do obiektu Cow. Przez utrzymywanie silnej referencji do obiektu SoftReference utrzymujesz miękką referencję do obiektu Cow.
Rysunek 9-4 pokazuje taki obiekt SoftReference który hermetyzuje miękką referencję do obiektu Cow. Obiekt SoftReference ma silne odniesienie od lokalnej zmiennej która jak wszystkie lokalne zmienne służy jako węzeł root dla garbage collectora. Jak wspomniano poprzednio referencje zawarte w węzłach root i instancjach zmiennych silnie osiągalnych obiektów są silnymi referencjami. Ponieważ obiekt SoftReference pokazany na rysunku 9-4 ma odniesienie przez silną referencję jest silnie osiągalny. Zakładając że ten obiekt zawiera tylko referencję do obiektu Cow, obiekt Cow jest miękkko osiągalny. Powodem tego że Cow jest miękko osiągalny jest to że garbage collector może jedynie osiągnąć obiekt Cow węzłów root przez przejście przez miękką referencję.

Rys. 9-4 Obiekt referencyjny i jego obiekt odniesienia (referent)
Skoro obiekt referencyjny jest utworzony będzie nadal trzymał jego miękką, słabą i fantomową referencję do jego referencta dotąd aż będzie wyczyszczony przez program lub garbage collector. Do wyczyszczenia obiektu referencyjnego program lub garbage collector potrzebuje wywołać clear(), metodę zdefiniowaną w classReference obiektu referencyjnego. Czyszczenie obiektu referencyjnego unieważnia miękką, słaba i fantomową referencję zawartą w tym obiekcie. Na przykład jeśli program lub garbage collector wywoła clear() na obiekcieSoftReference pokazanym na rysunku 9-4, miękka referencja do obiektu Cow zostanie uniważniona i obiekt Cow nie będzie dłużej miękko osiągalny.

Dodaj komentarz

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