Șapte tipuri de colectori de gunoi JAVA

Acest document va explica ce este colectorul de gunoi în java și principalele tipuri de colectori de gunoi cu comportamentele fiecărui colector de gunoi. De asemenea, vă rugăm să rețineți că în acest articol nu explic cum are loc alocarea heap-ului și cum pornesc colectorii de gunoi majori/minori. Se va explica în următorul articol.

Java este un limbaj de programare orientat pe obiecte care include colectarea automată a gunoiului. Java alocă și dezalocă automat memoria, astfel încât programele nu sunt împovărate cu această sarcină. Acum (Java-12), Java are șapte tipuri de colectori de gunoi,

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

  7. Colector de gunoi Z
  8. Shenandoah Garbage Collector

Cele de-al 5-lea și al 6-lea colector de gunoi au fost introduse în java 11, iar cel de-al 7-lea a fost introdus în java 12. În majoritatea aplicațiilor din producție s-au utilizat primele patru tipuri de colectoare de gunoi. Deoarece ultimele trei colectoare de gunoi au intrat recent în scenă.

Trebuie să ne facem griji în legătură cu GC-urile?

Da, într-adevăr. Trebuie să ne facem griji cu privire la GC și la comportamentele sale. Pentru că Acesta poate oferi o diferență semnificativă de performanță. Fiecare GC are propriile avantaje și dezavantaje. În calitate de dezvoltatori, trebuie să avem o idee clară despre comportamentele tuturor garbage collectorilor și trebuie să selectăm un garbage collector pe baza scenariului nostru de afaceri. Putem alege un garbage collector, trecând alegerea ca argument JVM.

Serial Garbage Collector

Aceasta este cea mai simplă implementare GC. În principiu, este concepută pentru un mediu cu un singur fir. Această implementare GC îngheață toate firele de execuție ale aplicației atunci când se execută. Folosește un singur fir pentru colectarea gunoiului. Prin urmare, nu este o idee bună să o folosim în aplicații cu mai multe fire, cum ar fi mediile de server.

Pentru a activa Serial Garbage Collector, putem folosi următorul argument:

java -XX:+UseSerialGC -jar Application.java

Parallel Garbage Collector

Colectorul de gunoi paralel este, de asemenea, numit și colector de randament. Spre deosebire de colectorul de gunoi serial, acesta utilizează mai multe fire de execuție pentru colectarea gunoiului. La fel ca și colectorul de gunoi serial, și acesta îngheață toate firele de execuție ale aplicației în timp ce efectuează colectarea gunoiului. Colectorul de gunoi se potrivește cel mai bine acelor aplicații care pot suporta pauzele aplicației.

Pentru a activa Garbage Collector paralel, putem folosi următorul argument:

java -XX:+UseParallelGC -jar Application.java

Dacă folosim acest GC, putem specifica numărul maxim de fire de colectare a gunoiului și timpul de pauză, randamentul și amprenta (dimensiunea heap)

Numărul de fire de colectare a gunoiului poate fi controlat cu opțiunea din linia de comandă

-XX:ParallelGCThreads=<N>

Obiectivul maxim al timpului de pauză (intervalul dintre două GC)se specifică cu opțiunea din linia de comandă

-XX:MaxGCPauseMillis=<N>

Obiectivul de randament maxim (măsurat în ceea ce privește timpul petrecut făcând garbage collection față de timpul petrecut în afara garbage collection) este specificat cu opțiunea de linie de comandă

-XX:GCTimeRatio=<N>

Amprenta maximă a heap footprint (cantitatea de memorie heap de care are nevoie un program în timpul rulării) se specifică cu ajutorul opțiunii -Xmx<N>.

CMS Garbage Collector

Concurrent Mark Sweep (CMS) garbage collector utilizează mai multe fire de colectare a gunoiului pentru colectarea gunoiului. Acesta scanează memoria heap pentru a marca instanțele pentru evacuare și apoi mătură instanțele marcate. Este conceput pentru aplicațiile care preferă pauze mai scurte de colectare a gunoiului și care își pot permite să împartă resursele procesorului cu colectorul de gunoi în timp ce aplicația este în curs de execuție.

Colectorul de gunoi CMS reține toate firele de execuție ale aplicației numai în următoarele două scenarii

  1. În timpul marcării obiectelor referite în spațiul de generație veche.
  2. Cu orice modificare a memoriei heap în paralel cu efectuarea colectării gunoiului

În comparație cu colectorul de gunoi paralel, colectorul CMS utilizează mai mult CPU pentru a asigura un randament mai bun al aplicației. Dacă putem aloca mai mult CPU pentru o performanță mai bună, atunci colectorul de gunoi CMS este alegerea preferată față de colectorul paralel.

Pentru a activa CMS Garbage Collector, putem folosi următorul argument:

java -XX:+USeParNewGC -jar Application.java

G1 Garbage Collector

G1 (Garbage First) Garbage Collector este conceput pentru aplicațiile care rulează pe mașini cu mai multe procesoare cu spațiu de memorie mare. Este disponibil începând cu JDK7 Update 4 și în versiunile ulterioare.

Separa memoria heap în regiuni și face colectarea în cadrul acestora în paralel. G1 face, de asemenea, compactarea spațiului heap liber din mers, imediat după ce recuperează memoria. Dar colectorul de gunoi CMS compactează memoria în situații de stop the world (STW). Colectorul G1 va înlocui colectorul CMS deoarece este mai eficient din punct de vedere al performanțelor.

În colectorul G1 conține două faze;

  1. Marcare
  2. Sweeping

În comparație cu alți colectori, colectorul G1 partiționează heap-ul într-un set de regiuni heap de dimensiuni egale, fiecare fiind un interval contigu de memorie virtuală. Atunci când efectuează colectarea gunoiului, G1 prezintă o fază de marcare globală concomitentă pentru a determina vivacitatea obiectelor din întregul heap.

După ce faza de marcare este finalizată, G1 știe care regiuni sunt în mare parte goale. El colectează mai întâi în aceste zone, ceea ce de obicei produce o cantitate semnificativă de spațiu liber. Acesta este motivul pentru care această metodă de colectare a gunoiului se numește Garbage-First.

Pentru a activa G1 Garbage Collector, putem folosi următorul argument:

java -XX:+UseG1GC -jar Application.java

Epsilon Garbage Collector

Epsilon este un garbage collector neoperațional sau pasiv. Acesta alocă memoria pentru aplicație, dar nu colectează obiectele neutilizate. Atunci când aplicația epuizează heap-ul Java, JVM-ul se oprește. Aceasta înseamnă că colectorul de gunoi Epsilon permite ca aplicațiile să rămână fără memorie și să se blocheze.

Scopul acestui colector de gunoi este măsurarea și gestionarea performanței aplicațiilor. Colectorii de gunoi activi sunt programe complexe care rulează în interiorul JVM alături de aplicația dumneavoastră. Epsilon elimină impactul pe care GC îl are asupra performanței. Nu există cicluri GC sau bariere de citire sau scriere. Atunci când se utilizează GC Epsilon, codul rulează în izolare. Epsilon ajută la vizualizarea modului în care garbage collection afectează performanța aplicației și care este pragul de memorie, deoarece va arăta când se termină. Ca exemplu Dacă credem că avem nevoie doar de un gigabyte de memorie pentru aplicația noastră, putem să o rulăm cu -Xmx1g și să vedem comportamentul. Dacă această alocare de memorie nu este suficientă, rulați-o din nou cu un heap dump. Rețineți că trebuie să activăm această opțiune pentru a obține un heap dump. Putem folosi acest argument pentru a obține un heap dump atunci când aplicația se blochează din cauza lipsei de memorie.

XX:HeapDumpOnOutOfMemoryError

Dacă trebuie să stoarcem fiecare bit de performanță din aplicația noastră, Epsilon ar putea fi cea mai bună opțiune pentru un GC. Dar trebuie să avem o înțelegere completă a modului în care codul nostru folosește memoria. Dacă acesta nu creează aproape deloc gunoi sau dacă știți exact câtă memorie folosește pentru perioada în care rulează, Epsilon este o opțiune viabilă.

Pentru a activa Epsilon Garbage Collector, putem folosi următorul argument:

java -XX:+UseEpsilonGC -jar Application.java

Z garbage collector

ZGC efectuează toate lucrările costisitoare concomitent, fără a opri execuția firelor de execuție ale aplicației pentru mai mult de 10ms, ceea ce îl face potrivit pentru aplicațiile care necesită o latență scăzută și/sau utilizează un heap foarte mare. Conform documentației Oracle, poate gestiona heap-uri de mai mulți terabyte. Oracle a introdus ZGC în Java 11. Colectorul de gunoi Z își execută ciclurile în firele sale. Acesta oprește aplicația pentru o medie de 1 ms. Colectorii G1 și Parallel au o medie de aproximativ 200 ms.

În Java 12, Oracle a adăugat corecții de performanță și descărcarea claselor, chiar dacă Z este încă în stare experimentală. Este disponibil numai pe Linux pe 64 de biți. Dar, ZGC profită de indicatorii pe 64 de biți cu o tehnică numită pointer coloring. Pointerii colorați stochează informații suplimentare despre obiectele de pe heap. Acesta este unul dintre motivele pentru care este limitat la JVM pe 64 de biți. Acest articol a fost explicat în profunzime acest scenariu (https://www.opsian.com/blog/javas-new-zgc-is-very-exciting/).

ZGC își face marcarea în trei faze.

1. Faza scurtă de oprire a lumii – Examinează rădăcinile GC, variabilele locale care punctează spre restul heap-ului. Numărul total al acestor rădăcini este de obicei minim și nu crește odată cu mărimea încărcăturii, astfel încât pauzele ZGC sunt foarte scurte și nu cresc pe măsură ce heap-ul crește.

2. Faza concurentă – Se plimbă prin graficul obiectelor și examinează indicatorii colorați, marcând obiectele accesibile. Bariera de sarcină previne concurența între faza GC și activitatea oricărei aplicații.

3. Faza de relocare – Mută obiectele vii pentru a elibera secțiuni mari din heap pentru a face alocări mai rapide. Când începe faza de relocare, ZGC împarte heap-ul în pagini și lucrează pe câte o pagină pe rând. Odată ce ZGC termină de mutat orice rădăcină, restul relocării are loc într-o fază concurentă.

ZGC va încerca să stabilească singur numărul de fire și, de obicei, are dreptate. Dar dacă ZGC are prea multe fire de execuție, vă va înfometa aplicația. Dacă nu are destule, veți crea gunoi mai repede decât îl poate colecta GC. Fazele lui ZGC ilustrează modul în care gestionează heaps mari fără a afecta performanța pe măsură ce memoria aplicației crește.

Pentru a activa Z Garbage Collector, putem folosi următorul argument:

java -XX:+UseZGC -jar Application.java

Shenandoah

Shenandoah este un colector de gunoi cu timp de pauză foarte redus care reduce timpii de pauză GC prin efectuarea mai multor activități de colectare a gunoiului concomitent cu programul Java în curs de execuție. CMS și G1 efectuează amândouă marcarea concomitentă a obiectelor active. Shenandoah adaugă compactarea concurentă.

Shenandoah utilizează regiuni de memorie pentru a gestiona care obiecte nu mai sunt utilizate și care sunt active și pregătite pentru compactare. Shenandoah adaugă, de asemenea, un pointer de redirecționare la fiecare obiect din heap și îl folosește pentru a controla accesul la obiect. Proiectarea Shenandoah face schimb de cicluri CPU concurente și spațiu pentru îmbunătățiri ale timpului de pauză. Pointerul de redirecționare facilitează mutarea obiectelor, dar mișcările agresive înseamnă că Shenandoah utilizează mai multă memorie și necesită mai multă muncă în paralel decât alte GC-uri. Dar face munca suplimentară cu pauze foarte scurte de oprire a lumii.

Shenandoah procesează heap-ul în mai multe faze mici, dintre care majoritatea sunt concurente cu aplicația. Acest design face posibil ca GC să gestioneze eficient un heap mare.

  1. Prima pauză stop-the-world din ciclu. Se pregătește heap-ul pentru marcarea concurentă și se scanează setul rădăcină. La fel caZGC, durata acestei pauze corespunde dimensiunii setului rădăcină, nu a heap-ului.
  2. În continuare, o fază concurentă parcurge heap-ul și identifică obiectele accesibile și inaccesibile.
  3. A treia finalizează procesul de marcare prin golirea actualizărilor de heap în așteptare și scanarea din nou a setului rădăcină. Această fază declanșează a doua pauză „stop-the-world” din ciclu. Numărul de actualizări în așteptare și dimensiunea setului rădăcină determină cât de lungă este pauza.
  4. Apoi, o altă fază concurentă copiază obiectele din regiunile identificate în faza finală de marcare. Acest proces diferențiază Shenandoah de alte GC-uri, deoarece compactează în mod agresiv heap-ul în paralel cu firele de execuție ale aplicației.
  5. Perioada următoare declanșează a treia (și cea mai scurtă) pauză din ciclu. Aceasta se asigură că toate firele GC au terminat evacuarea.
  6. Când se termină, o fază concurentă parcurge heap-ul și actualizează referințele la obiectele mutate mai devreme în ciclu.
  7. Ultima pauză de oprire a lumii din ciclu finalizează actualizarea referințelor prin actualizarea setului rădăcină. În același timp, ea reciclează regiunile evacuate.
  8. În cele din urmă, ultima fază recuperează regiunile evacuate, care acum nu mai au referințe în ele.

Potem configura Shenandoah cu una dintre cele trei euristici. Acestea guvernează momentul în care GC își începe ciclurile și modul în care selectează regiunile pentru evacuare.

1. Adaptiv: Observă ciclurile GC și începe următorul ciclu astfel încât acesta să se finalizeze înainte ca aplicația să epuizeze heap-ul. Această euristică este modul implicit.

2. Static: Pornește un ciclu GC pe baza ocupării heap-ului și a presiunii de alocare.

3. Compact: Rulează cicluri GC în mod continuu. Shenandoah pornește un nou ciclu imediat ce se termină cel precedent sau pe baza cantității de heap-alocate de la ultimul ciclu. Această euristică generează o suprasolicitare a randamentului, dar oferă cea mai bună recuperare de spațiu.

Shenandoah trebuie să colecteze heap mai repede decât îl alocă aplicația pe care o deservește. Dacă presiunea de alocare este prea mare și nu există suficient spațiu pentru noi alocări, se va produce un eșec. Shenandoah are mecanisme configurabile pentru această situație.

  • Pacing: Dacă Shenandoah începe să rămână în urma ritmului de alocare, va bloca firele de alocare pentru a recupera. De obicei, blocajele sunt suficiente pentru vârfuri ușoare de alocare. Shenandoah introduce întârzieri de 10 ms sau mai puțin. Dacă pacing eșuează, Shenandoah va trece la următorul pas: GC degenerat.
  • GC degenerat: Dacă apare un eșec de alocare, Shenandoah începe o fază de oprire a lumii. Folosește această fază pentru a finaliza ciclul GC curent. Deoarece un stop-the-world nu se luptă cu aplicația pentru resurse, ciclul ar trebui să se termine rapid și să elimine deficitul de alocare. Adesea, un ciclu degenerat are loc după ce cea mai mare parte a activității ciclului este deja finalizată, astfel încât stop-the-world este de scurtă durată. Totuși, jurnalul GC o va raporta ca o pauză completă.
  • GC complet: Dacă atât pacing-ul cât și un GC degenerat eșuează, Shenandoah revine la un ciclu GC complet. Acest GC final garantează că aplicația nu va eșua cu o eroare de out-of-memory decât dacă nu a mai rămas niciun heap.

Shenandoah oferă aceleași avantaje ca și ZGC cu heap-uri mari, dar mai multe opțiuni de reglare. În funcție de natura aplicației dumneavoastră, diferitele euristici se pot potrivi bine. Timpii săi de pauză s-ar putea să nu fie la fel de scurți ca ai lui ZGC, dar sunt mai previzibili.

Pentru a activa Shenandoah Garbage Collector, putem folosi următorul argument:

java -XX:+UseShenanodoahC -jar Application.java

Concluzie

Scopul acestui articol este de a rezuma toate colectoarele de gunoi. Prin urmare, unele părți din conținut au fost extrase din referințele date. Trebuie să avem o idee clară despre colectorii de gunoi pentru a selecta un colector de gunoi optim pentru cazurile de utilizare a aplicației noastre. Colectorul de gunoi optim va îmbunătăți semnificativ performanța aplicației noastre.

Referință

  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/

Lasă un răspuns

Adresa ta de email nu va fi publicată.