Seven Types of JAVA Garbage Collectors

Ten dokument wyjaśni czym jest garbage collector w java i główne typy garbage collectorów z zachowaniem każdego garbage collectora. Należy również pamiętać, że w tym artykule nie wyjaśniam, jak alokacja sterty dzieje i główne / mniejsze garbage collectors rozpocząć. Wyjaśnię to w następnym artykule.

Java jest obiektowo zorientowanym językiem programowania, który zawiera Automatic Garbage Collection. Java automatycznie alokuje i deallokuje pamięć, więc programy nie są obciążone tym zadaniem. Obecnie (Java-12), Java ma siedem typów garbage collectorów,

  1. Serial Garbage Collector
  2. Parallel Garbage Collector
  3. CMS Garbage Collector
  4. G1 Garbage Collector
  5. Epsilon Garbage Collector
  6. .

  7. Z garbage collector
  8. Shenandoah Garbage Collector

5-ty i 6-ty garbage collector zostały wprowadzone w java 11, a 7-my został wprowadzony w java 12. W większości aplikacji w produkcji używał pierwszych czterech typów garbage collectors. Odkąd ostatnie trzy garbage collectory niedawno weszły do obrazu.

Czy musimy się martwić o GC?

Tak, rzeczywiście. Musimy się martwić o GC i jego zachowanie. Ponieważ może to zapewnić znaczącą różnicę w wydajności. Każdy GC ma swoje własne wady i zalety. Jako programiści, musimy mieć jasne pojęcie o zachowaniach wszystkich garbage collectorów i musimy wybrać garbage collector w oparciu o nasz scenariusz biznesowy. Możemy wybrać garbage collector przez, przekazując wybór jako argument JVM.

Serial Garbage Collector

Jest to najprostsza implementacja GC. Jest ona zasadniczo przeznaczona dla środowiska z jednym wątkiem. Ta implementacja GC zamraża wszystkie wątki aplikacji, gdy jest uruchomiona. Używa pojedynczego wątku do zbierania śmieci. Dlatego też nie jest dobrym pomysłem używanie jej w aplikacjach wielowątkowych, takich jak środowiska serwerowe.

Aby włączyć Serial Garbage Collector, możemy użyć następującego argumentu:

java -XX:+UseSerialGC -jar Application.java

Parallel Garbage Collector

Paralelny garbage collector jest również nazywany kolektorem przelotowym. W przeciwieństwie do seryjnego garbage collectora, ten używa wielu wątków do zbierania śmieci. Podobne do szeregowego garbage collector to również zamraża wszystkie wątki aplikacji podczas wykonywania garbage collection. Garbage collector jest odpowiedni dla tych aplikacji, które mogą znieść przerwy w działaniu aplikacji.

Aby włączyć równoległy Garbage Collector, możemy użyć następującego argumentu:

java -XX:+UseParallelGC -jar Application.java

Jeśli używamy tego GC, możemy określić maksymalną liczbę wątków odśmiecania i czas wstrzymania, przepustowość i ślad (rozmiar sterty)

Liczbę wątków odśmiecania można kontrolować za pomocą opcji wiersza poleceń

-XX:ParallelGCThreads=<N>

Maksymalny cel czasu pauzy (przerwy między dwoma GC)określa się za pomocą opcji wiersza poleceń

-XX:MaxGCPauseMillis=<N>

Cel maksymalnej przepustowości (mierzony w odniesieniu do czasu spędzonego na robieniu garbage collection w stosunku do czasu spędzonego poza garbage collection) jest określony opcją wiersza poleceń

-XX:GCTimeRatio=<N>

Maksymalny ślad sterty (ilość pamięci sterty, jakiej wymaga program podczas działania) jest określany za pomocą opcji -Xmx<N>.

CMS Garbage Collector

Concurrent Mark Sweep (CMS) garbage collector używa wielu wątków garbage collectora do zbierania śmieci. Skanuje pamięć sterty, aby oznaczyć instancje do eksmisji, a następnie zamiata oznaczone instancje. Jest on przeznaczony dla aplikacji, które preferują krótsze przerwy w odśmiecaniu i które mogą sobie pozwolić na współdzielenie zasobów procesora z odśmiecaczem podczas działania aplikacji.

Odśmiecacz CMS wstrzymuje wszystkie wątki aplikacji tylko w następujących dwóch scenariuszach

  1. Podczas oznaczania obiektów odniesienia w przestrzeni starego pokolenia.
  2. Każda zmiana w pamięci sterty równolegle z wykonywaniem odśmiecania

W porównaniu z równoległym odśmiecaniem, kolektor CMS wykorzystuje więcej procesora, aby zapewnić lepszą przepustowość aplikacji. Jeśli możemy przydzielić więcej CPU dla lepszej wydajności, wtedy CMS garbage collector jest preferowanym wyborem w stosunku do równoległego kolektora.

Aby włączyć CMS Garbage Collector, możemy użyć następującego argumentu:

java -XX:+USeParNewGC -jar Application.java

G1 Garbage Collector

G1 (Garbage First) Garbage Collector jest przeznaczony dla aplikacji działających na maszynach wieloprocesorowych z dużą przestrzenią pamięci. Jest dostępny od JDK7 Update 4 i w późniejszych wydaniach.

Oddziela pamięć sterty na regiony i wykonuje zbieranie w nich równolegle. G1 również kompaktuje wolną przestrzeń sterty zaraz po odzyskaniu pamięci. Natomiast garbage collector CMS kompaktuje pamięć w sytuacjach typu stop the world (STW). Kolektor G1 zastąpi kolektor CMS, ponieważ jest bardziej wydajny.

W G1 kolektor zawiera dwie fazy;

  1. Zaznaczanie
  2. Zamiatanie

W przeciwieństwie do innych kolektorów, kolektor G1 dzieli stertę na zestaw równej wielkości regionów sterty, z których każdy jest przyległym zakresem pamięci wirtualnej. Podczas wykonywania zbierania śmieci G1 wykonuje równoczesną fazę globalnego znakowania w celu określenia żywotności obiektów na całej stercie.

Po zakończeniu fazy znakowania G1 wie, które regiony są w większości puste. Zbiera w tych obszarach w pierwszej kolejności, co zwykle daje znaczną ilość wolnego miejsca. Dlatego właśnie ta metoda zbierania śmieci jest nazywana Garbage-First.

Aby włączyć G1 Garbage Collector, możemy użyć następującego argumentu:

java -XX:+UseG1GC -jar Application.java

Epsilon Garbage Collector

Epsilon jest nieoperacyjnym lub pasywnym garbage collectorem. Alokuje on pamięć dla aplikacji, ale nie zbiera nieużywanych obiektów. Gdy aplikacja wyczerpie stertę Javy, JVM wyłącza się. Oznacza to, że Epsilon garbage collector pozwala, aby aplikacjom zabrakło pamięci i uległy awarii.

Celem tego garbage collectora jest pomiar i zarządzanie wydajnością aplikacji. Aktywne garbage collectory to złożone programy, które działają wewnątrz JVM obok Twojej aplikacji. Epsilon usuwa wpływ GC na wydajność. Nie ma cykli GC ani barier odczytu i zapisu. Kiedy używasz GC Epsilon, kod działa w izolacji. Epsilon pomaga wizualizować jak garbage collection wpływa na wydajność aplikacji i jaki jest próg pamięci, ponieważ pokazuje kiedy się ona kończy. Jako przykład, jeśli uważamy, że potrzebujemy tylko jednego gigabajta pamięci dla naszej aplikacji, możemy uruchomić ją z opcją -Xmx1g i zobaczyć jej zachowanie. Jeśli ta alokacja pamięci nie jest wystarczająca, uruchom ją ponownie z heap dump. Proszę zauważyć, że musimy włączyć tę opcję, aby uzyskać zrzut sterty. Możemy użyć tego argumentu, aby uzyskać zrzut sterty, gdy aplikacja zawiesza się z powodu braku pamięci.

XX:HeapDumpOnOutOfMemoryError

Jeśli musimy wycisnąć każdy bit wydajności z naszej aplikacji, Epsilon może być najlepszą opcją dla GC. Ale musimy mieć pełne zrozumienie tego, jak nasz kod używa pamięci. Jeśli nie tworzy on prawie żadnych śmieci lub wiesz dokładnie, ile pamięci używa w okresie, w którym działa, Epsilon jest realną opcją.

Aby włączyć Epsilon Garbage Collector, możemy użyć następującego argumentu:

java -XX:+UseEpsilonGC -jar Application.java

Z garbage collector

ZGC wykonuje wszystkie kosztowne prace współbieżnie, bez zatrzymywania wykonywania wątków aplikacji na dłużej niż 10ms, co czyni go odpowiednim dla aplikacji wymagających niskiego opóźnienia i/lub wykorzystujących bardzo dużą stertę. Zgodnie z dokumentacją Oracle, może on obsługiwać sterty wieloterabajtowe. Oracle wprowadził ZGC w Javie 11. Z garbage collector wykonuje swoje cykle w swoich wątkach. Wstrzymuje pracę aplikacji średnio na 1 ms. Kolektory G1 i Parallel średnio około 200 ms.

W Javie 12, Oracle dodał poprawki wydajności i rozładowywanie klas, mimo że Z jest nadal w statusie eksperymentalnym. Jest on dostępny tylko na 64-bitowym Linuksie. Ale ZGC korzysta z 64-bitowych wskaźników za pomocą techniki zwanej kolorowaniem wskaźników. Kolorowane wskaźniki przechowują dodatkowe informacje o obiektach na stercie. Jest to jeden z powodów, dla których jest on ograniczony do 64-bitowej JVM. W tym artykule ten scenariusz został głęboko wyjaśniony (https://www.opsian.com/blog/javas-new-zgc-is-very-exciting/).

ZGC wykonuje swoje znakowanie w trzech fazach.

1. Krótka faza stop-the-world – Bada korzenie GC, zmienne lokalne, które wskazują na resztę sterty. Łączna liczba tych korzeni jest zwykle minimalna i nie skaluje się wraz z wielkością obciążenia, więc pauzy ZGC są bardzo krótkie i nie zwiększają się wraz ze wzrostem sterty.

2. Faza współbieżna – Przemierza graf obiektów i bada kolorowe wskaźniki, oznaczając dostępne obiekty. Bariera obciążenia zapobiega rywalizacji między fazą GC a aktywnością dowolnej aplikacji.

3. Faza relokacji – Przenosi żywe obiekty, aby zwolnić duże sekcje sterty, dzięki czemu alokacje są szybsze. Gdy rozpoczyna się faza relokacji, ZGC dzieli stertę na strony i pracuje na jednej stronie na raz. Gdy ZGC zakończy przenoszenie korzeni, reszta relokacji odbywa się w fazie współbieżnej.

ZGC będzie próbowało samo ustawić liczbę wątków i zwykle ma rację. Ale jeśli ZGC ma zbyt wiele wątków, zagłodzi twoją aplikację. Jeśli nie ma ich wystarczająco dużo, będziesz tworzyć śmieci szybciej niż GC może je zebrać. Fazy ZGC ilustrują, jak zarządza on dużymi stertami bez wpływu na wydajność, gdy pamięć aplikacji rośnie.

Aby włączyć Z Garbage Collector, możemy użyć następującego argumentu:

java -XX:+UseZGC -jar Application.java

Shenandoah

Shenandoah to garbage collector o ultra niskim czasie wstrzymania, który redukuje czasy wstrzymania GC poprzez wykonywanie większej ilości zadań odśmiecania współbieżnie z uruchomionym programem Java. CMS i G1 wykonują współbieżne znakowanie żywych obiektów. Shenandoah dodaje współbieżne zagęszczanie.

Shenandoah używa regionów pamięci do zarządzania, które obiekty nie są już w użyciu, a które są żywe i gotowe do kompresji. Shenandoah dodaje również wskaźnik przekierowania do każdego obiektu sterty i używa go do kontrolowania dostępu do obiektu. Projekt Shenandoah handluje współbieżnymi cyklami procesora i przestrzenią na rzecz poprawy czasu wstrzymania. Wskaźnik przekierowania ułatwia przenoszenie obiektów, ale agresywne ruchy oznaczają, że Shenandoah używa więcej pamięci i wymaga więcej pracy równoległej niż inne GC. Ale wykonuje tę dodatkową pracę z bardzo krótkimi pauzami typu stop-the-world.

Shenandoah przetwarza stertę w wielu małych fazach, z których większość jest współbieżna z aplikacją. Taka konstrukcja umożliwia GC efektywne zarządzanie dużą stertą.

  1. Pierwsza pauza stop-the-world w cyklu. Przygotowuje stertę do znakowania współbieżnego i skanuje zbiór główny. Podobnie jak w przypadkuZGC, długość tej pauzy odpowiada rozmiarowi zbioru głównego, a nie sterty.
  2. Następna, współbieżna faza przemierza stertę i identyfikuje osiągalne i nieosiągalne obiekty.
  3. Trzecia kończy proces znakowania przez opróżnienie oczekujących aktualizacji sterty i ponowne przeskanowanie zbioru głównego. Ta faza wyzwala drugą pauzę stop-the-world w cyklu. Liczba oczekujących aktualizacji i rozmiar zbioru głównego określają, jak długa jest ta pauza.
  4. Następnie, kolejna współbieżna faza kopiuje obiekty z regionów zidentyfikowanych w końcowej fazie znakowania. Proces ten odróżnia Shenandoah od innych GC, ponieważ agresywnie zagęszcza stertę równolegle z wątkami aplikacji.
  5. Kolejna faza wyzwala trzecią (i najkrótszą) pauzę w cyklu. Zapewnia ona, że wszystkie wątki GC zakończyły ewakuację.
  6. Kiedy kończy, współbieżna faza chodzi po stercie i aktualizuje odniesienia do obiektów przeniesionych wcześniej w cyklu.
  7. Ostatnia pauza stop-the-world w cyklu kończy aktualizację odniesień przez aktualizację zbioru głównego. Jednocześnie poddaje recyklingowi ewakuowane regiony.
  8. Na koniec ostatnia faza odzyskuje ewakuowane regiony, które teraz nie mają w sobie żadnych referencji.

Możemy skonfigurować Shenandoah za pomocą jednej z trzech heurystyk. Regulują one, kiedy GC rozpoczyna swoje cykle i jak wybiera regiony do ewakuacji.

1. Adaptacyjna: Obserwuje cykle GC i rozpoczyna następny cykl tak, aby zakończył się, zanim aplikacja wyczerpie stertę. Ta heurystyka jest trybem domyślnym.

2. Statyczny: Uruchamia cykl GC na podstawie zajętości sterty i nacisku na alokację.

3. Compact: Uruchamia cykle GC w sposób ciągły. Shenandoah rozpoczyna nowy cykl jak tylko poprzedni się zakończy lub na podstawie ilości sterty zaalokowanej od ostatniego cyklu. Ta heurystyka powoduje narzut na przepustowość, ale zapewnia najlepszą rekultywację przestrzeni.

Shenandoah musi zbierać stertę szybciej, niż alokuje ją aplikacja, którą obsługuje. Jeśli nacisk na alokację jest zbyt duży i nie ma wystarczająco dużo miejsca na nowe alokacje, nastąpi awaria. Shenandoah ma konfigurowalne mechanizmy na taką sytuację.

  • Pacing: Jeśli Shenandoah zacznie nie nadążać za tempem alokacji, będzie przeciągać wątki alokacji, aby nadrobić zaległości. Te przeciągnięcia są zwykle wystarczające dla łagodnych skoków alokacji. Shenandoah wprowadza opóźnienia rzędu 10ms lub mniejsze. Jeśli pacing się nie powiedzie, Shenandoah przejdzie do następnego kroku: zdegenerowanego GC.
  • Zdegenerowane GC: Jeśli wystąpi awaria alokacji, Shenandoah rozpoczyna fazę stop-the-world. Wykorzystuje tę fazę do zakończenia bieżącego cyklu GC. Ponieważ stop-the-world nie walczy z aplikacją o zasoby, cykl ten powinien zakończyć się szybko i usunąć braki w alokacji. Często zdegenerowany cykl występuje po tym, jak większość pracy cyklu została już zakończona, więc zatrzymanie-the-world jest krótkie. Dziennik GC zgłosi to jednak jako pełną pauzę.
  • Pełna GC: Jeśli zarówno pacing, jak i zdegenerowana GC zawiodą, Shenandoah wraca do pełnego cyklu GC. To ostateczne GC gwarantuje, że aplikacja nie zawiedzie z błędem out-of-memory, chyba że nie pozostanie żadna sterta.

Shenandoah oferuje te same zalety co ZGC z dużymi stertami, ale więcej opcji dostrajania. W zależności od charakteru twojej aplikacji, różne heurystyki mogą być dobrym dopasowaniem. Jego czasy wstrzymania mogą nie być tak krótkie jak ZGC, ale są bardziej przewidywalne.

Aby włączyć Shenandoah Garbage Collector, możemy użyć następującego argumentu:

java -XX:+UseShenanodoahC -jar Application.java

Wniosek

Celem tego artykułu jest podsumowanie wszystkich garbage collectorów. Stąd niektóre części treści zostały wyodrębnione z podanych referencji. Musimy mieć jasne pojęcie o garbage collectors, aby wybrać optymalny garbage collector dla naszych przypadków użycia aplikacji. Optymalny garbage collector znacznie poprawi wydajność naszej aplikacji.

Referencje

  1. https://www.oracle.com/webfolder/technetwork/tutorials/obe/java/gc01/index.html
  2. https://www.baeldung.com/jvm-garbage-collectors
  3. https://dzone.com/articles/java-garbage-collection-3
  4. https://www.opsian.com/blog/javas-new-zgc-is-very-exciting/
  5. https://openjdk.java.net/projects/shenandoah/
  6. https://docs.oracle.com/en/java/javase/12/gctuning/z-garbage-collector1.html#GUID-A5A42691-095E-47BA-B6DC-FB4E5FAA43D0
  7. http://clojure-goes-fast.com/blog/shenandoah-in-production/

.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany.