Zeven types van JAVA-afvalverzamelaars

In dit document wordt uitgelegd wat de afvalverzamelaar in java is en wat de belangrijkste types afvalverzamelaars zijn met het gedrag van elke afvalverzamelaar. In dit artikel leg ik niet uit hoe heap-allocatie gebeurt en hoe major/minor garbage collectors starten. Het zal uitleggen in het volgende artikel.

Java is een object-georiënteerde programmeertaal die Automatische Garbage Collection bevat. Java wijst automatisch geheugen toe en wijst het toe, zodat programma’s niet met die taak worden belast. Nu (Java-12), Java heeft zeven soorten garbage collectors,

  1. Serial Garbage Collector
  2. Parallel Garbage Collector
  3. CMS Garbage Collector
  4. G1 Garbage Collector
  5. Epsilon Garbage Collector
  6. Z garbage collector
  7. Shenandoah Garbage Collector

De 5e en 6e garbage collectors zijn in java 11 geïntroduceerd en de 7e is in java 12 geïntroduceerd. In de meeste toepassingen in de productie heeft gebruik gemaakt van de eerste vier soorten garbage collectors. Sinds de laatste drie garbage collectors recent in beeld zijn gekomen.

Moeten we ons zorgen maken over GC’s?

Ja, inderdaad. We moeten ons zorgen maken over de GC en zijn gedrag. Omdat het een significant verschil in prestatie kan opleveren. Elke GC heeft zijn eigen voor- en nadelen. Als ontwikkelaars moeten we een duidelijk idee hebben van het gedrag van alle garbage collectors en moeten we een garbage collector kiezen op basis van ons bedrijfsscenario. Wij kunnen een garbage collector kiezen door, de keuze als een JVM argument door te geven.

Serial Garbage Collector

Dit is de eenvoudigste GC implementatie. Het is in principe ontworpen voor een single thread omgeving. Deze GC implementatie bevriest alle applicatie threads wanneer het loopt. Het gebruikt enkele draad voor vuilnisophaling. Daarom is het geen goed idee om het in multi-threaded toepassingen zoals serveromgevingen te gebruiken.

Om de seriële vuilnisman in te schakelen, kunnen we het volgende argument gebruiken:

java -XX:+UseSerialGC -jar Application.java

Parallelle vuilnisman

De parallelle vuilnisman wordt ook wel een doorvoer-verzamelaar genoemd. In tegenstelling tot de seriële garbage collector, gebruikt deze meerdere threads voor garbage collection. Net als de seriële garbage collector bevriest deze ook alle applicatie-threads tijdens het uitvoeren van garbage collection. De vuilnisman is het meest geschikt voor toepassingen die toepassingspauzes kunnen verdragen.

Om de parallelle vuilnisman in te schakelen, kunnen we het volgende argument gebruiken:

java -XX:+UseParallelGC -jar Application.java

Als we deze GC gebruiken, kunnen we maximale garbage collection-threads en pauzetijd, doorvoer en voetafdruk (heapgrootte)

Het aantal garbage collector-threads kan worden geregeld met de opdrachtregeloptie

-XX:ParallelGCThreads=<N>

Het doel voor de maximale pauzetijd (het gat tussen twee GC) kan worden opgegeven met de opdrachtregeloptie

-XX:MaxGCPauseMillis=<N>

Het maximale doorvoerdoel (gemeten aan de hand van de tijd die wordt besteed aan garbage collection versus de tijd die buiten garbage collection wordt doorgebracht) wordt opgegeven met de commandoregeloptie

-XX:GCTimeRatio=<N>

Een maximale heap footprint (de hoeveelheid heap-geheugen die een programma nodig heeft tijdens het uitvoeren) wordt opgegeven met de optie -Xmx<N>.

CMS-afvalverzamelaar

Concurrent Mark Sweep (CMS) afvalverzamelaar gebruikt meerdere garbage collector threads voor afvalverzameling. Het scant het heap geheugen om instanties te markeren voor evictie en veegt dan de gemarkeerde instanties. Het is ontworpen voor toepassingen die de voorkeur geven aan kortere vuilnisophaalpauzes, en die het zich kunnen veroorloven om processorbronnen te delen met de vuilnisman terwijl de toepassing draait.

CMS-afvalverzamelaar houdt alle toepassingsthreads alleen in de volgende twee scenario’s

  1. Tijdens het markeren van de objecten waarnaar wordt verwezen in de oude generatieruimte.
  2. Alle veranderingen in het heap geheugen parallel aan het doen van de garbage collection

In vergelijking met de parallelle garbage collector, gebruikt CMS collector meer CPU om een betere applicatie doorvoer te garanderen. Als we meer CPU kunnen toewijzen voor betere prestaties, dan verdient de CMS-afvalverzamelaar de voorkeur boven de parallelle verzamelaar.

Om de CMS-afvalverzamelaar in te schakelen, kunnen we het volgende argument gebruiken:

java -XX:+USeParNewGC -jar Application.java

G1 Garbage Collector

G1 (Garbage First) Garbage Collector is ontworpen voor toepassingen die op multiprocessormachines met veel geheugenruimte worden uitgevoerd. Het is beschikbaar sinds JDK7 Update 4 en in latere releases.

Het verdeelt het heap-geheugen in regio’s en verzamelt daarbinnen parallel. G1 comprimeert ook de vrije heap ruimte onderweg, net na het terugwinnen van het geheugen. Maar CMS vuilnisman comprimeert het geheugen op stop de wereld (STW) situaties. G1 verzamelaar zal de CMS verzamelaar vervangen omdat het meer prestatie efficiënt is.

In G1 verzamelaar bevat twee fasen;

  1. Marking
  2. Sweeping

In tegenstelling tot andere verzamelaars, G1 verzamelaar verdeelt de heap in een set van gelijke grootte heap regio’s, elk een aaneengesloten bereik van virtueel geheugen. Bij het uitvoeren van afvalverzamelingen, toont G1 een gelijktijdige globale markeringsfase om de levendigheid van objecten in de hele heap te bepalen.

Nadat de markeringsfase is voltooid, weet G1 welke regio’s het meest leeg zijn. Het verzamelt eerst in deze gebieden, wat meestal een aanzienlijke hoeveelheid vrije ruimte oplevert. Daarom wordt deze methode van vuilnisverzameling Garbage-First genoemd.

Om G1 vuilnisverzamelaar in te schakelen, kunnen we het volgende argument gebruiken:

java -XX:+UseG1GC -jar Application.java

Epsilon vuilnisverzamelaar

Epsilon is een niet-operationele of een passieve vuilnisverzamelaar. Het wijst het geheugen voor de toepassing toe, maar verzamelt niet de ongebruikte objecten. Wanneer de toepassing de Java heap uitput, sluit de JVM af. Dit betekent dat de Epsilon vuilnisman applicaties zonder geheugen laat zitten en laat crashen.

Het doel van deze vuilnisman is het meten en beheren van de prestaties van applicaties. Actieve vuilnismannen zijn complexe programma’s die in de JVM naast uw applicatie draaien. Epsilon verwijdert de impact die GC heeft op de prestaties. Er zijn geen GC cycles of lees of schrijf barrières. Wanneer de Epsilon GC gebruikt wordt, draait de code in isolatie. Epsilon helpt om te visualiseren hoe garbage collection de prestaties van de app beïnvloedt en wat de geheugen drempel is aangezien het zal tonen wanneer het opraakt. Als we bijvoorbeeld denken dat we maar één gigabyte geheugen nodig hebben voor onze applicatie, kunnen we het draaien met -Xmx1g en het gedrag zien. Als die geheugentoewijzing niet voldoende is, voer het dan opnieuw uit met een heap dump. Merk op dat we deze optie moeten aanzetten om een heap dump te krijgen. We kunnen dit argument gebruiken om een heap dump te krijgen als de applicatie crasht door een tekort aan geheugen.

XX:HeapDumpOnOutOfMemoryError

Als we elk beetje prestatie uit onze applicatie willen halen, is Epsilon misschien wel de beste optie voor een GC. Maar we moeten een volledig begrip hebben van hoe onze code geheugen gebruikt. Als het bijna geen vuilnis creëert of als u precies weet hoeveel geheugen het gebruikt voor de periode waarin het draait, is Epsilon een uitvoerbare optie.

Om Epsilon Garbage Collector in te schakelen, kunnen we het volgende argument gebruiken:

java -XX:+UseEpsilonGC -jar Application.java

Z garbage collector

ZGC voert al het dure werk gelijktijdig uit, zonder de uitvoering van toepassingsthreads langer dan 10 ms te stoppen, waardoor het geschikt is voor toepassingen die een lage latency vereisen en/of een zeer grote heap gebruiken. Volgens de Oracle documentatie kan het multi-terabyte heaps aan. Oracle introduceerde ZGC in Java 11. De Z garbage collector voert zijn cycli uit in zijn threads. Hij pauzeert de applicatie gemiddeld 1 ms. De G1- en Parallel-verzamelaars hebben een gemiddelde van ongeveer 200 ms.

In Java 12 voegde Oracle prestatieverbeteringen en class unloading toe, hoewel Z nog steeds een experimentele status heeft. Het is alleen beschikbaar op 64-bit Linux. Maar ZGC maakt gebruik van 64-bit pointers met een techniek genaamd pointer coloring. Gekleurde pointers slaan extra informatie op over objecten op de heap. Dit is een van de redenen waarom het beperkt is tot de 64-bit JVM. In dit artikel is dit scenario diepgaand uitgelegd (https://www.opsian.com/blog/javas-new-zgc-is-very-exciting/).

ZGC doet zijn markering in drie fasen.

1. Korte stop-de-wereld fase – Het onderzoekt de GC wortels, lokale variabelen die naar de rest van de heap wijzen. Het totale aantal van deze wortels is meestal minimaal en schaalt niet met de grootte van de belasting, dus ZGC’s pauzes zijn erg kort en nemen niet toe als je heap groeit.

2. Concurrent fase – Het loopt de object grafiek en onderzoekt de gekleurde pointers, het markeren van toegankelijke objecten. De belastingbarrière voorkomt onenigheid tussen de GC-fase en de activiteit van een applicatie.

3. Verplaatsingsfase – Het verplaatst levende objecten om grote secties van de heap vrij te maken om toewijzingen sneller te maken. Wanneer de verplaatsingsfase begint, verdeelt ZGC de heap in pagina’s en werkt aan één pagina per keer. Zodra ZGC klaar is met het verplaatsen van wortels, gebeurt de rest van de verhuizing in een gelijktijdige fase.

ZGC zal proberen om het aantal threads zelf in te stellen, en meestal is dat juist. Maar als ZGC te veel threads heeft, zal het je applicatie uithongeren. Als het er niet genoeg heeft, zal je sneller vuilnis maken dan de GC het kan verzamelen. De fasen van ZGC laten zien hoe het grote heaps beheert zonder de prestaties te beïnvloeden als het applicatiegeheugen groeit.

Om Z Garbage Collector in te schakelen, kunnen we het volgende argument gebruiken:

java -XX:+UseZGC -jar Application.java

Shenandoah

Shenandoah is een vuilnisverzamelaar met een ultralage pauzetijd die de pauzetijden van GC verkort door meer vuilnisverzamelwerk gelijktijdig uit te voeren met het draaiende Java-programma. CMS en G1 doen beide gelijktijdige markering van levende objecten. Shenandoah voegt gelijktijdige compactie toe.

Shenandoah gebruikt geheugenregio’s om te beheren welke objecten niet langer in gebruik zijn en welke levend zijn en klaar voor compressie. Shenandoah voegt ook een forwarding pointer toe aan elk heap object en gebruikt deze om de toegang tot het object te controleren. Het ontwerp van Shenandoah verruilt gelijktijdige CPU cycli en ruimte voor verbeteringen in de pauzetijd. De forwarding pointer maakt het makkelijk om objecten te verplaatsen, maar de agressieve bewegingen betekenen dat Shenandoah meer geheugen gebruikt en meer parallel werk vereist dan andere GC’s. Maar het doet het extra werk met zeer korte stop-de-wereld pauzes.

Shenandoah verwerkt de heap in vele kleine fasen, waarvan de meeste gelijktijdig met de applicatie. Dit ontwerp maakt het mogelijk voor de GC om een grote heap efficiënt te beheren.

  1. Eerste stop-de-wereld pauze in de cyclus. Deze maakt de heap klaar voor concurrent markering en scant de root set. Net als bijZGC komt de lengte van deze pauze overeen met de grootte van de root set, niet met de heap.
  2. Volgende, een gelijktijdige fase doorloopt de heap en identificeert bereikbare en onbereikbare objecten.
  3. De derde beëindigt het markeerproces door hangende heap-updates af te voeren en de root set opnieuw te scannen. Deze fase leidt tot de tweede stop-de-wereld pauze in de cyclus. Het aantal in behandeling zijnde updates en de grootte van de root set bepalen hoe lang de pauze duurt.
  4. Dan kopieert een andere gelijktijdige fase de objecten uit de gebieden die in de laatste markeerfase zijn geïdentificeerd. Dit proces onderscheidt Shenandoah van andere GC’s, omdat het de heap parallel met applicatie-threads agressief comprimeert.
  5. De volgende fase leidt tot de derde (en kortste) pauze in de cyclus. Het zorgt ervoor dat alle GC-threads klaar zijn met evacueren.
  6. Als het klaar is, loopt een gelijktijdige fase de heap af en werkt verwijzingen bij naar objecten die eerder in de cyclus zijn verplaatst.
  7. De laatste stop-de-wereld pauze in de cyclus voltooit het bijwerken van de verwijzingen door de root set bij te werken. Tegelijkertijd worden de geëvacueerde regio’s gerecycled.
  8. Ten slotte worden in de laatste fase de geëvacueerde regio’s teruggehaald, die nu geen referenties meer hebben.

We kunnen Shenandoah configureren met een van de drie heuristieken. Zij bepalen wanneer de GC zijn cycli start en hoe het regio’s selecteert voor evacuatie.

1. Adaptief: Observeert GC-cycli en start de volgende cyclus zodat deze is voltooid voordat de applicatie de heap heeft opgebruikt. Deze heuristiek is de standaard mode.

2. Statisch: Start een GC-cyclus op basis van heapbezetting en allocatiedruk.

3. Compact: Voert GC-cycli continu uit. Shenandoah start een nieuwe cyclus zodra de vorige is afgelopen of gebaseerd op de hoeveelheid heap-allocatie sinds de laatste cyclus. Deze heuristiek veroorzaakt doorvoer overhead maar biedt de beste ruimte terugwinning.

Shenandoah moet heap sneller verzamelen dan de applicatie die het bedient deze toewijst. Als de toewijzingsdruk te hoog is en er niet genoeg ruimte is voor nieuwe toewijzingen, zal er een storing optreden. Shenandoah heeft configureerbare mechanismen voor deze situatie.

  • Pacing: Als Shenandoah achter begint te raken op het tempo van toewijzing, zal het toewijzingsdraden stallen om ze in te halen. De stalls zijn meestal genoeg voor milde toewijzingspieken. Shenandoah introduceert vertragingen van 10ms of minder. Als pacing faalt, gaat Shenandoah naar de volgende stap: ontaarde GC.
  • Ontaarde GC: Als een allocatiefout optreedt, start Shenandoah een stop-de-wereld fase. Het gebruikt de fase om de huidige GC-cyclus te voltooien. Omdat een stop-de-wereld niet met de applicatie vecht voor bronnen, zou de cyclus snel moeten eindigen en het toewijzingstekort opheffen. Vaak gebeurt een gedegenereerde cyclus nadat het meeste werk van de cyclus al is voltooid, dus de stop-de-wereld is kort. Het GC-log zal het echter als een volledige pauze rapporteren.
  • Full GC: Als zowel pacing als een gedegenereerde GC falen, valt Shenandoah terug op een volledige GC-cyclus. Deze laatste GC garandeert dat de applicatie niet faalt met een out-of-memory error tenzij er geen heap meer over is.

Shenandoah biedt dezelfde voordelen als ZGC met grote heaps maar meer afstemmingsopties. Afhankelijk van de aard van uw toepassing, kunnen de verschillende heuristieken een goede match zijn. De pauzetijden zijn misschien niet zo kort als die van ZGC, maar ze zijn voorspelbaarder.

Om de Shenandoah Garbage Collector in te schakelen, kunnen we het volgende argument gebruiken:

java -XX:+UseShenanodoahC -jar Application.java

Conclusie

Het doel van dit artikel is om een overzicht te geven van alle garbage collectors. Daarom zijn enkele inhoudelijke delen uit de gegeven referenties gehaald. We moeten een duidelijk idee hebben van de garbage collectors om een optimale garbage collector te selecteren voor onze applicatie gebruikssituaties. De optimale vuilnisman zal de prestaties van onze toepassing aanzienlijk verbeteren.

Reference

  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/

Geef een antwoord

Het e-mailadres wordt niet gepubliceerd.