JavaRush /Blog Java /Random-PL /Więcej o śmieciarce w Javie

Więcej o śmieciarce w Javie

Opublikowano w grupie Random-PL
Cześć! Na ostatnim wykładzie po raz pierwszy zapoznaliśmy się z wbudowanym mechanizmem języka Java – śmieciarzem. Działa w tle podczas działania programu, zbierając niepotrzebne obiekty, które później zostaną usunięte. W ten sposób zwalnia się pamięć do tworzenia nowych obiektów w przyszłości. W tym wykładzie przyjrzymy się bliżej zasadzie jego działania. Na przykład, jak i w którym momencie obiekt staje się niepotrzebny? A skąd śmieciarz o tym wie? Odpowiemy na te pytania :) Nasz wykład ma raczej charakter przeglądowy: tego materiału nie trzeba uczyć się na pamięć. Ma na celu poszerzenie horyzontów w zakresie pracy pamięci i śmieciarki, więc wystarczy ją przeczytać i dowiedzieć się czegoś nowego dla siebie :) Do dzieła! Pierwszą rzeczą, o której musisz pamiętać, jest to, że moduł zbierający elementy bezużyteczne działa równolegle z twoim programem . Nie jest jego częścią i funkcjonuje osobno: aby to opisać, w ostatnim wykładzie podaliśmy analogię z robotem odkurzającym. W rzeczywistości nie zawsze tak było. Poprzednio moduł zbierający elementy bezużyteczne był projektowany w taki sposób, że działał w tym samym wątku, co Twój program. I według jakiegoś harmonogramu co kilka minut zaczynał sprawdzać obecność w programie niepotrzebnych obiektów. Problem polegał na tym, że podczas tego sprawdzania i usuwania śmieci program zawieszał się i nie wykonywał. Wyobraź sobie, że siedzisz w biurze w pracy. Ale wtedy przychodzi sprzątaczka i musi umyć podłogi w pokoju. Wykopuje Cię zza komputera na 5 minut, a Ty czekasz, aż skończy sprzątać. W tym czasie nie możesz pracować. Mniej więcej tak kiedyś działały śmieciarki :) Później mechanizm ten uległ zmianie i teraz śmieciarka działa w tle, nie spowalniając pracy samego programu. Już wiesz, że obiekt umiera, gdy nie ma już do niego żadnych odniesień. Ale moduł zbierający elementy bezużyteczne w rzeczywistości nie liczy odniesień do plików . Po pierwsze, może być dość długi. Po drugie, jest mało skuteczny. Przecież przedmioty mogą się do siebie odnosić! Więcej o śmieciarce - 2Rysunek pokazuje przykład, w którym 3 obiekty odwołują się do siebie, ale nikt inny się do nich nie odwołuje. Oznacza to, że nie są one potrzebne do działania reszty programu. Gdyby moduł zbierający elementy bezużyteczne po prostu liczył odniesienia, wszystkie te 3 obiekty pozostałyby i nie zwalniałyby pamięci: istnieją odniesienia do nich! Można to porównać do statku kosmicznego. Podczas lotu astronauci postanowili sprawdzić listę części zamiennych do naprawy i znaleźli wśród nich kierownicę i pedały ze zwykłego samochodu. Najwyraźniej nie są tutaj potrzebne i zajmują dodatkową przestrzeń. Choć części te są ze sobą powiązane i pełnią pewne funkcje, w ramach eksploatacji statku kosmicznego stanowią zbędny śmieci, którego lepiej się pozbyć. Dlatego Java zdecydowała się stworzyć podstawę do zbierania śmieci nie licząc referencji, ale dzieląc obiekty na dwa typy - osiągalne i nieosiągalne. Jak ustalić, czy obiekt jest osiągalny? Wszystko genialne jest proste. Obiekt jest osiągalny, jeśli odwołuje się do niego inny osiągalny obiekt. W rezultacie powstaje „łańcuch osiągalności”. Rozpoczyna się wraz z uruchomieniem programu i trwa przez cały czas jego działania. Wygląda to mniej więcej tak: Więcej o śmieciarce - 4Strzałka na rysunku wskazuje kod wykonawczy naszego programu. W kodzie np. w metodzie main() tworzone są referencje do obiektów. Obiekty te mogą odnosić się do nowych obiektów, te do kolejnych i tak dalej. Tworzy się łańcuch powiązań obiektowych . Jeśli do obiektu można dotrzeć poprzez ten łańcuch łączy prowadzących do „łącza głównego”, to znaczy takiego, który jest tworzony bezpośrednio w wykonywającym kodzie, uznaje się go za osiągalny. Na naszym zdjęciu są one zaznaczone na niebiesko. Jeśli jednak obiekt wypadł z tego łańcucha, czyli żadna ze zmiennych w aktualnie wykonywanym kodzie nie zawiera odniesień do niego, a także nie da się do niego dotrzeć poprzez „łańcuch powiązań” – uważa się go za nieosiągalny. W naszym programie dwa takie obiekty zaznaczono na czerwono. Uwaga: te „czerwone” obiekty są ze sobą powiązane. Jednak, jak powiedzieliśmy wcześniej, nowoczesny moduł zbierający elementy bezużyteczne w Javie nie zlicza referencji. Określa , czy obiekt jest osiągalny czy nieosiągalny . Dlatego jego ofiarą staną się dwa czerwone obiekty na obrazku. Przyjrzyjmy się teraz całemu procesowi od początku do końca, a przy okazji zobaczmy jak działa pamięć w Javie :) Wszystkie obiekty w Javie przechowywane są w specjalnym obszarze pamięci zwanym stertą . W potocznym języku „sterta” to góra przedmiotów, w której wszystko leży w chaosie. Ale sterta w Javie taka nie jest. Ma bardzo logiczną i rozsądną strukturę. Pewnego pięknego dnia programiści Java odkryli, że wszystkie obiekty w ich programach można podzielić na dwa typy – stosunkowo proste i „długowieczne” . Obiekty „długowieczne” to takie, które przetrwały wiele zbiórek śmieci. Najczęściej będą istnieć do końca programu. W rezultacie wspólna sterta, na której przechowywane są wszystkie utworzone obiekty, została podzielona na kilka części. Pierwsza część ma piękną nazwę – Eden (biblijny „Ogród Edenu”). To świetna nazwa, ponieważ to tutaj trafiają obiekty po ich utworzeniu. To w tej części podczas pisania przydzielana jest pamięć dla nowych obiektównew. Obiektów można utworzyć wiele, a gdy w tym obszarze zabraknie miejsca, rozpoczyna się pierwsze, „szybkie” zbieranie śmieci. Trzeba przyznać, że śmieciarka jest bardzo sprytna i wybiera algorytm pracy w zależności od tego, czego jest więcej na stercie – śmieci czy działających obiektów. Jeśli prawie wszystkie obiekty są śmieciami, moduł zbierający zaznacza „żywe” obiekty i przenosi je do innego obszaru pamięci, po czym bieżący obszar jest całkowicie czyszczony. Jeśli śmieci jest mało i większość zajmują przedmioty żywe, zaznacza śmieci, sprząta je i porządkuje pozostałe przedmioty. Powiedzieliśmy, że „kolekcjoner zaznacza „żywe” obiekty i przenosi je w inne miejsce w pamięci”, ale które? Obszar pamięci, do którego przenoszone są wszystkie obiekty, które przetrwały co najmniej jedno wyrzucanie elementów bezużytecznych, nazywany jest Przestrzenią Przetrwania . Przestrzeń Przetrwania z kolei podzielona jest na pokolenia . Każdemu obiektowi przypisana jest generacja na podstawie liczby operacji wyrzucania elementów bezużytecznych, które wystąpiły. Jeśli jest, należy do „Generacji 1”, jeśli 5 – do „Pokolenia 5”. Razem Eden i Survival Space tworzą obszar o nazwie Młode Pokolenie . Oprócz Młodego Pokolenia na stosie znajduje się jeszcze jeden obszar pamięci – Stare Pokolenie („stare pokolenie”). Są to obiekty bardzo długowieczne, które przetrwały wiele zbiórek śmieci. Bardziej opłaca się przechowywać je oddzielnie od wszystkich pozostałych. I tylko wtedy, gdy obszar Starej Generacji będzie zapełniony, czyli tj. Nawet w programie jest tak wiele długowiecznych obiektów, że nie ma wystarczającej ilości pamięci, przeprowadzane jest pełne odśmiecanie. Przetwarza nie tylko jeden obszar pamięci, ale ogólnie wszystkie obiekty utworzone przez maszynę Java. Naturalnie wymaga to znacznie więcej czasu i zasobów. Dlatego zdecydowano się przechowywać przedmioty długowieczne oddzielnie. Gdy w innych obszarach zabraknie miejsca, przeprowadzana jest tzw. „szybka zbiórka śmieci”. Obejmuje tylko jeden obszar, dzięki czemu jest bardziej ekonomiczna i szybsza. Na koniec, gdy nawet strefa dla stulatków jest już zapchana, do walki wkracza pełne sprzątanie. Tym samym najbardziej „ciężkie” narzędzie asemblera wykorzystywane jest tylko wtedy, gdy nie jest już potrzebne. Schematycznie struktura sterty i czyszczenia wygląda następująco: Więcej o śmieciarce - 5
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION