Garbage collection

Garbage collection

Istnieją dwie strategie zarządzaniem pamięcią dynamiczną. Pierwsza strategia polega na obarczeniu tą odpowiedzialnością programistę. To programista tworzy i czyści pamięć na stercie. Niewątpliwie jest to wydajne rozwiązania, ale mniej czytelne i wygodne podczas wytwarzania kodu. Przykładem języka programowania, który używa takiego sposobu jest C/C++. Druga strategia polega na przeniesieniu tej odpowiedzialności do niezależnego modułu działającego obok wykonywanego programu. To właśnie ta strategia została zaimplementowana w Javie. Dlatego w odróżnieniu od niektórych języków programowania, programista pisząc w języku Java nie musi martwić się o zwalnianie pamięci, ponieważ maszyna wirtualna Javy robi to za niego. Jednym z mechanizmów używanych do tych celów przez wirtualną maszynę Javy jest Garbage Collector, w skrócie GC.

W tym artykule znajdziesz odpowiedzi na poniższe pytania:

  • Jakie istnieją możliwości zarządzania stertą?
  • Czym jest Garbage Collector?
  • Za co odpowiedzialny jest Garbage Collector?
  • Jakie istnieją moduły do oczyszczania pamięci?
  • Czym różnią się moduły do oczyszczania pamięci?

Zadaniem Garbage Collector’a jest dbanie o alokowaną pamięć, czyszczenie z nieużywanych plików oraz wydajność aplikacji. Moduł Garbage Collector towarzyszy od początku Javy i rozwija się wraz z nowymi wydaniami. Aby zrozumieć działanie i wprowadzone zmiany w modułach GC trzeba najpierw zrozumieć, jak dzieli się obszar pamięci w Javie.

Działanie GC

Do rozwiązania problemu oczyszczania pamięci dynamicznej opracowano wiele rodzajów algorytmów. Jednym z nich jest algorytm wektorowy, który polega na reprezentowaniu obiektów i zależności jako grafy. Taki mechanizm został zaadaptowany w Javie. Większość powstałych modułów Garbage Collector pracuje podobnie i w uproszczeniu proces wygląda następująco:

  • W pierwszym kroku, algorytm szuka obiektów źródłowych, które będą korzeniami w grafie. Korzeniem może być uruchomiony wątek albo zmienna lokalna.
  • W następnym kroku algorytm przechodzi po korzeniach i oznacza obiekty jako używane.
  • Następnie algorytm ponownie przegląda zaznaczone korzenie, ale tym razem zaznacza wszystkie powiązane z nim obiekty jako używany.
  • Na koniec iteruje po wszystkich obiektach z pamięci i sprawdza czy taki obiekt został oznaczony. Jeśli obiekt nie został oznaczony, to wtedy zostaje usunięty z pamięci.
  • Opcjonalnym krokiem jest reorganizacja pamięci programu, aby uniknąć fragmentacji.

W dużym skrócie moduł znajduje wszystkie żywe obiekty, usuwa pozostałe i ewentualnie reorganizuje pamięć.

Cechy modułów GC

Moduły do czyszczenia pamięci możemy podzielić według kilku kategorii. Poniżej znajdują się najważniejsze z nich.

Tryb pracy

Moduły oczyszczania pamięci w Javie możemy podzielić na cztery kategorie w zależności od trybu pracy:

  • tryb szeregowy – wszystkie wątki są zatrzymywane, a wyłączny dostęp do pamięci ma wątek GC,
  • tryb równoległy – wszystkie wątki są zatrzymywane, a wyłączny dostęp do pamięci mają wątki GC. Różni się od trybu szeregowego zwiększoną ilością wątków dla GC,
  • tryb współbieżny – pozwala na dalsze wykonywanie wątków aplikacyjnych z jednoczesnym uruchomieniem wątków GC. Taki tryb nie zatrzymuje aplikacji, a jedynie zmniejsza przepustowość.
  • tryb przyrostowy – wykonywanie na zmianę wątki aplikacyjne i GC.
Podział modułów do czyszczenia pamięci w zależności od trybu pracy

Sposób usuwania nieużywanych obiektów

Oprócz podziału na tryb pracy, moduły czyszczenia pamięci klasyfikuje się według sposobu usuwania nieużywanych obiektów. Wyróżniamy:

  • Mark-Sweep – w pierwszym kroku oznacza obiekty używane przez wirtualną maszynę, a następnie czyści pamięć, usuwając obiekty porzucone w pierwszym kroku,
  • Mark-Sweep-Compact – wykonuje te same kroki jakie w Mark-Sweep, z tą różnicą, że dokonuje realokację danych tak aby pamięć nie pozostała pofragmentowana,
  • Mark-Copy – kopiuje używane obiekty do nowego miejsca na stercie.
Podział modułów do czyszczenia pamięci w zależności od sposobu usuwania nieużywanych obiektów

Zasięg pracy

W poprzednim artykule został omówiony podział sterty na generacje: młoda i starą. Nie bez powodu utworzono taki podział. W każdej z tych części można obrać inną strategię usuwania nieużywanych obiektów i promowania do wyższej generacji. Przykładowo wychodząc z założenia, że większość obiektów szybko staje się nieużyteczna, można zastosować lokalne optymalizacje na odpowiednim poziomie generacji.

Jeśli wiemy, że tylko ułamek obszaru zostanie oznaczony jako żywe obiekty na poziomie młodej generacji, to warto wtedy zastosować kopiowanie żywych obiektów do nowej przestrzeni niż usuwać i robić realokację.

Wyróżniamy 3 rodzaje kolekcji z punktu widzenia GC:

  • mała kolekcja (minor GC) – obejmuje młodą generację i GC uruchamiany jest w przypadku zapełnienia obszaru młodej generacji;
  • duża kolekcja (major GC) – obejmuje starą generacje i GC uruchamiany jest w przypadku zapełnienia obszaru starej generacji;
  • pełnia kolekcja (full GC) – obejmuje całą stertę

Efekty uboczne

W zależności od wybranego trybu pracy i strategii usuwania nieosiągalnych obiektów, pojawiają się następujące problemy wydajnościowe:

  • przepustowość – zmniejszenie rzeczywistej szybkości wykonywania wątków aplikacyjnych,
  • latencja – opóźnienie w działaniu programu, wynikająca z przerwania wątków aplikacyjnych na rzecz uruchomienia wątków modułu oczyszczenia pamięci,
  • fragmentacja pamięci – efekt uboczny, powstały po czyszczeniu pamięci. Problem fragmentacji pamięci jest uzależniony od wyboru strategii usuwania nieużywanych obiektów. Nierozwiązanie tego problemu, będzie powodowało, że JVM będzie spędzał więcej czasu na szukaniu odpowiedniego miejsca do alokowania obiektu.

Przy wyborze trybu pracy zawsze wybieramy pomiędzy przepustowością a latencją, zaś wybór strategii usuwania nieużywanych obiektów wpływa głównie na efekt pofragmentowanej pamięci.

Aktywne moduły GC

W Javie wersji 11, JVM HotSpot oferuje cztery moduły do oczyszczania pamięci:

  • Serial Garbage Collector (SerialGC),
  • Parallel Garbage Collector (ParallelGC),
  • CMS Garbage Collector (CMSGC),
  • G1 Garbage Collector (G1GC).

W Javie 17, lista modułów GC nieco różni się od powyższej. Lista aktywnych modułów GC została wzbogacona o The Z Garbage Collector oraz Shenandoah Garbage Collector, a CMS Garbage Collector został usunięty.

W zależności od potrzeby można wybrać jeden z nich. Jeśli użytkownik nie wybierze konkretnego modułu do oczyszczania pamięci to wirtualna maszyna ustawi domyślny, który może różnić się w zależności od wersji Javy.

Wersja JavyDomyślny GCLista dostępnych GC
Java 6Serial GC / Parallel GC ( client / server ) Serial GC, Parallel GC, CMSGC, G1GC
Java 7Serial GC / Parallel GC ( client / server ) SerialGC, ParallelGC, CMSGC, G1GC
Java 8 LTS Serial GC / Parallel GC ( client / server ) Serial GC, Parallel GC, CMSGC, G1GC
Java 9G1GCSerial GC, Parallel GC, CMSGC, G1GC
Java 10G1GC Serial GC, Parallel GC, CMSGC, G1GC, Epsilon, ZGC
Java 11 LTS G1GC Serial GC, Parallel GC, CMSGC, G1GC, Epsilon, ZGC
Java 12 G1GC Serial GC, Parallel GC, CMSGC, G1GC, Epsilon, ZGC, Shenandoah
Java 13 G1GC Serial GC, Parallel GC, CMSGC, G1GC, Epsilon, ZGC, Shenandoah
Java 14 G1GC Serial GC, Parallel GC, G1GC, Epsilon, ZGC, Shenandoah
Java 15 G1GC Serial GC, Parallel GC, G1GC, Epsilon, ZGC, Shenandoah
Java 16 G1GC Serial GC, Parallel GC, G1GC, Epsilon, ZGC, Shenandoah
Java 17 LTSG1GC Serial GC, Parallel GC, G1GC, Epsilon, ZGC, Shenandoah
Historia modułów GC

Ciekawe artykuły

  1. A. Altvater,  Co to jest Java Garbage Collection? Jak to działa, sprawdzone metody, samouczki i nie tylko, https://stackify.com/what-is-java-garbage-collection
  2. M. Marczak, JVM Garbage Collector. Wprowadzenie, https://bulldogjob.pl/news/404-jvm-garbage-collector-wprowadzenie
  3. J. Kubryński, Co każdy programista Java powinien wiedzieć o JVM: zarządzanie pamięcią, https://bottega.com.pl/pdf/materialy/jvm/jvm2.pdf
  4. S. Nayak, Garbage Collection in Java – What is GC and How it Works in the JVM, https://www.freecodecamp.org/news/garbage-collection-in-java-what-is-gc-and-how-it-works-in-the-jvm
  5. J. Bosiacki – Wrocław JUG, Rodzaje GC w Javie 11 i krótkie wprowadzenie do ZGC. – Jacek Bosiacki, https://www.youtube.com/watch?v=zeRSZTMuR2c&ab_channel=Wroc%C5%82awJUG
  6. Oracle Corporation, Available Collectors, https://docs.oracle.com/en/java/javase/17/gctuning/available-collectors.html
  7. N. Salnikov-Tarnovski, Minor GC vs Major GC vs Full GC, https://dzone.com/articles/minor-gc-vs-major-gc-vs-full

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *