Java ma bardzo przyjemny mechanizm – Garbage Collector. Jest to dodatkowy program uruchamiany przez wirtualną maszynę po to, aby czyścić pamięć ze starych, nieużywanych obiektów. Gdyby nie on, kolejne tworzone obiekty lądowałyby na stercie tak długo, aż aplikacja zajęłaby całą pamięć, co uniemożliwiłoby jej pracę. Dzięki GC nie musimy się specjalnie zamartwiać alokacją i zwalnianiem pamięci. Od Javy 9 standardem jest Garbage Collector zwany G1GC (Garbage First GC), który wprowadzony był już wcześniej, jednak jeszcze wtedy nie był domyślnym czyścicielem w JDK. Na czym polega? Jak działa?
G1GC – podstawy
G1GC wprowadzony został eksperymentalnie pod koniec istnienia Javy 1.6, a od siódmej wersji języka wprowadzony jest jako oficjalny (choć jeszcze nie domyślny) GC – to się wydarzyło dopiero od JDK 9. W tym collectorze domyślny pause-target (zatrzymanie się aplikacji w celu wyczyszczenia pamięci) ustawiony jest na 200ms, jednak jest to modyfikowalne, aby zapewnić jak najlepszy kompromis między wydajnością a przepustowością aplikacji. Sterta dzielona jest na 2048 regionów o rozmiarze odpowiednim do rozmiarów dostępnej dla aplikacji pamięci. Rozmiar regionów ustawiany jest przez JVP podczas startu aplikacji (lub przez programistę za pomocą odpowiedniej flagi uruchomieniowej), pomiędzy 1 a 32 MB w potęgach 2 (2MB dla stosu 4GB, 4MB dla 8GB itd).
G1GC – subregiony
Garbage 1st Garbage Collector pracuje na fragmentach sterty zamiast na całej dostępnej pamięci. Fragmenty te określane są jako Eden, Survivor, Old lub Humongous (ogromny – w którym znajdują się elementy zajmujące powyżej połowy regionu).
-
-
- EDEN – w tych regionach tworzone są nowe obiekty
- SURVIVAL – jeśli obiekt będący w EDEN przeżyje pierwsze czyszczenie – jest przesyłany do regionu SURVIVAL i następnie poddany dalszej obróbce podczas kolejnych iteracji
- OLD – po “przeżyciu” kilku czyszczeń w regionie oznaczonym jako SURVIVAL – obiekt przenoszony jest do OLD
- HUMONGOUS – gdy GC podczas czyszczenia znajdzie obiekt zajmujący powyżej pół regionu, automatycznie wysyła go do regionu HUMONGOUS. HUMONGOUS to zestaw kolejnych regionów zaczynających się od StartHumongous i trwający przez kolejne ContinousHumongous.
-
G1GC – jak to działa?
-
- Aplikacja startuje i nowe obiekty są alokowane w regionach EDEN
- Aplikacja tworzy więcej i więcej obiektów, po czym pierwsza iteracja GC ma miejsce (young collection – młoda / wczesna kolekcja)
- podczas tej fazy, GC znajduje żywe obiekty w regionach EDEN i kopiuje je do SURVIVAL. Regiony EDEN są potem czyszczone z martwych obiektów
- Mają miejsce kolejne iteracje, obiekty z EDEN przenoszone są do SURVIVAL, a obiekty z SURVIVAL – czyszczone lub zostawiane w spokoju
- Po kilku iteracjach, gdy obiekt w SURVIVAL jest nadal żywy – jest kopiowany do OLD
- Po początkowej przewadze subregionów EDEN, z czasem, gdy obiekty przeżywają kolejne iteracje, zaczyna przybywać regionów OLD, doprowadzając do ich przewagi
- Od tego czasu (gdy sterta jest zajęta w min. 45%) uruchamiana jest faza późnej (starej?) kolecji (old generation collection)
- GC rozpoczyna cykl oceniania równoległego, który ma oddzielić używane i nieużywane obiekty z OLD – nieużywane umierają, używane – mogą nadal zostać w OLD
- Co ważne – aplikacja nadal się nie zatrzymuje. Wszystkie elementy są wykonywane równolegle
- Po zakończeniu czyszczenia całość od punktu 3 zaczyna się na nowo
G1GC – ustawienia
Flaga | Wartość domyślna | Opis |
-XX:G1HeapRegionSize=n | 2048 | Rozmiar regionu, na które dzielona jest sterta |
-XX:MaxGCPauseMillis=n | 200 | Maksymalny pause-time |
-XX:G1NewSizePercent=n | 5 | Minimalny procent sterty dla fazy “young collection”. OPCJA EKSPERYMENTALNA |
-XX:G1MaxNewSizePercent=n | 60 | Jak wyżej, ale jest to maksymalny procent zajęcia sterty. OPCJA EKSPERYMENTALNA |
-XX:ParallelGcThreads=n | – | Ilość wątków GC |
-XX:ConcGCThreads=n | – | Ilość wątków oceniających obiekty |
-XX:InitialHeapOccupancyPercent = n | 45 | Procent zajęcia sterty wymuszający cykl oceniania |
-XX:G1MixedGCLiveThresholdPercent=n | 60 | Procent zajęcia sterty wymuszający “cykl mieszany” |
-XX:G1HeapWastePercent=n | 10 | Minimalny procent odzysku, powyżej którego uruchamiane jest czyszczenie. Gdy procent możliwy do odzyskania jest mniejszy niż określony – JVM nie uruchomi GC. |
-XX:G1MixedGCCountTarget=n | 8 | Maksymalna liczba mieszanych kolekcji obiektów |
-XX:G1OldCSetRegionThresholdPercent=n | 10 | Górny limit regionów OLD zbieranych podczas cyklu mieszanego |
-XX:G1ReservePercent=n | 10 | Procent wolnej pamięci w rezerwie, aby zmniejszyć ryzyko przepełnienia pamięci |
G1GC – Rekomendacje Oracle
-
-
- Staraj się unikać jawnego ustawiania rozmiaru “young generation” – pamiętaj, że ustawianie go ma wpływ na pause-time
- Jeśli chodzi o pause-time – podczas ustawiania GC należy znaleźć kompromis między wydajnością a przepustowością. G1GC ma docelową przepustowość 90% pracy apliikacji, 10% GC. Ustawienie zbyt agresywnego celu pauzy może podnieść koszt czyszczenia obniżając przepustowość, natomiast zbyt konserwatywnego – zmniejszyć wydajność poprzez zajęcie pamięci
- Nie bój się eksperymentować z ustawieniami, szczególnie dotyczącymi momentu uruchamiania GC i rozmiarów odzysku, aby znaleźć najlepszy kompromis dla Twojej aplikacji
-