Sju typer av JAVA Garbage Collectors

Det här dokumentet kommer att förklara vad en garbage collector i java är och vilka huvudtyper av garbage collectors som finns med beteenden för varje garbage collector. Observera också att jag i den här artikeln inte förklarar hur heap-allokering sker och hur stora/minor garbage collectors startar. Det kommer att förklaras i nästa artikel.

Java är ett objektorienterat programmeringsspråk som innehåller automatisk garbage collection. Java allokerar och deallokerar minnet automatiskt så att programmen inte belastas med den uppgiften. Nu (Java-12) har Java sju typer av garbage collectors,

  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:e och 6:e garbage collector har införts i java 11 och 7:e har införts i java 12. I de flesta produktionsprogram används de fyra första typerna av skräpplockare. Eftersom de tre sista garbage collectors nyligen kommit in i bilden.

Behövs vi oroa oss för GC:s?

Ja, verkligen. Vi måste oroa oss för GC och dess beteenden. Eftersom den kan ge en betydande prestandaskillnad. Varje GC har sina egna fördelar och nackdelar. Som utvecklare måste vi ha en klar uppfattning om beteendena hos alla garbage collectors och vi måste välja en garbage collector utifrån vårt affärsscenario. Vi kan välja en garbage collector genom att skicka valet som ett JVM-argument.

Serial Garbage Collector

Detta är den enklaste GC-implementationen. Den är i princip utformad för en miljö med en enda tråd. Denna GC-implementering fryser alla programtrådar när den körs. Den använder en enda tråd för sophämtning. Därför är det ingen bra idé att använda den i program med flera trådar som servermiljöer.

För att aktivera Serial Garbage Collector kan vi använda följande argument:

java -XX:+UseSerialGC -jar Application.java

Parallel Garbage Collector

Den parallella skräpinsamlaren kallas också för en genomströmningsinsamlare. Till skillnad från den seriella sophämtaren använder den här flera trådar för sophämtning. I likhet med den seriella skräpplockaren fryser den också alla programtrådar när den utför skräpplockning. Skräpplockaren lämpar sig bäst för de program som tål pauser.

För att aktivera parallell skräpplockare kan vi använda följande argument:

java -XX:+UseParallelGC -jar Application.java

Om vi använder denna GC kan vi ange maximalt antal trådar för sophämtning och paustid, genomströmning och fotavtryck (heapstorlek)

Antalet trådar för sophämtning kan styras med kommandoradsalternativet

-XX:ParallelGCThreads=<N>

Det maximala målet för paustid (mellanrum mellan två GC) anges med kommandoradsalternativet

-XX:MaxGCPauseMillis=<N>

Det maximala genomströmningsmålet (mätt med avseende på den tid som spenderas på sophämtning jämfört med den tid som spenderas utanför sophämtning) specificeras med kommandoradsalternativet

-XX:GCTimeRatio=<N>

Det maximala heap-avtrycket (mängden heap-minne som ett program kräver när det körs) anges med hjälp av alternativet -Xmx<N>.

CMS Garbage Collector

Concurrent Mark Sweep (CMS) garbage collector använder flera garbage collector trådar för sophämtning. Den genomsöker heapminnet för att markera instanser som ska utvisas och sveper sedan de markerade instanserna. Den är utformad för program som föredrar kortare pauser för sophämtning och som har råd att dela processorresurser med sophämtaren medan programmet körs.

CMS-soptömmaren håller alla programtrådar endast i följande två scenarier

  1. Under markeringen av de refererade objekten i det gamla generationsutrymmet.
  2. Alla ändringar i heapminnet parallellt med att man gör sophämtningen

I jämförelse med den parallella sophämtaren använder CMS-hämtaren mer CPU för att säkerställa bättre applikationsgenomströmning. Om vi kan allokera mer CPU för bättre prestanda är CMS garbage collector att föredra framför den parallella samlaren.

För att aktivera CMS Garbage Collector kan vi använda följande argument:

java -XX:+USeParNewGC -jar Application.java

G1 Garbage Collector

G1 (Garbage First) Garbage Collector är utformad för program som körs på maskiner med flera processorer och stort minnesutrymme. Den är tillgänglig sedan JDK7 Update 4 och i senare versioner.

Den delar upp heapminnet i regioner och gör insamlingen inom dem parallellt. G1 komprimerar också det fria heaputrymmet i farten strax efter det att minnet återkrävts. Men CMS garbage collector komprimerar minnet i STW-situationer (stop the world). G1-samlaren kommer att ersätta CMS-samlaren eftersom den är mer prestandasnål.

I G1-samlaren innehåller två faser;

  1. Markering
  2. Svepning

Till skillnad från andra samlare delar G1-samlaren upp högen i en uppsättning av högenregioner av samma storlek, som var och en är ett sammanhängande område av virtuellt minne. När G1 utför sophämtning visar G1 en samtidig global markeringsfas för att avgöra hur levande objekten är i hela högen.

När markeringsfasen är avslutad vet G1 vilka regioner som är mestadels tomma. Den samlar in i dessa områden först, vilket vanligtvis ger en betydande mängd ledigt utrymme. Det är därför denna metod för sophämtning kallas Garbage-First.

För att aktivera G1 Garbage Collector kan vi använda följande argument:

java -XX:+UseG1GC -jar Application.java

Epsilon Garbage Collector

Epsilon är en icke-operativ eller en passiv garbage collector. Den allokerar minnet för programmet, men samlar inte in de oanvända objekten. När programmet uttömmer Java heap stängs JVM:en av. Det innebär att Epsilon garbage collector tillåter att programmen får slut på minne och kraschar.

Syftet med denna garbage collector är att mäta och hantera programprestanda. Aktiva skräpplockare är komplexa program som körs i JVM tillsammans med programmet. Epsilon tar bort den inverkan som GC har på prestandan. Det finns inga GC-cykler eller läs- eller skrivbarriärer. När Epsilons GC används körs koden i isolering. Epsilon hjälper till att visualisera hur garbage collection påverkar appens prestanda och vad är minneströskeln eftersom den visar när den tar slut. Som exempel Om vi tror att vi bara behöver en gigabyte minne för vår applikation kan vi köra den med -Xmx1g och se beteendet. Om den minnesallokeringen inte är tillräcklig kan vi köra den på nytt med en heapdump. Observera att vi måste aktivera det här alternativet för att få en heapdump. Vi kan använda det här argumentet för att få en heapdump när programmet kraschar på grund av för lite minne.

XX:HeapDumpOnOutOfMemoryError

Om vi behöver pressa varje bit av prestanda ur vårt program kan Epsilon vara ditt bästa alternativ för en GC. Men vi måste ha en fullständig förståelse för hur vår kod använder minnet. Om den nästan inte skapar något skräp eller om du vet exakt hur mycket minne den använder under den period den körs är Epsilon ett bra alternativ.

För att aktivera Epsilon Garbage Collector kan vi använda följande argument:

java -XX:+UseEpsilonGC -jar Application.java

Z garbage collector

ZGC utför allt dyrt arbete samtidigt, utan att stoppa exekveringen av applikationstrådar i mer än 10 ms, vilket gör den lämplig för applikationer som kräver låg latenstid och/eller använder en mycket stor heap. Enligt Oracles dokumentation kan den hantera heaps på flera terabyte. Oracle införde ZGC i Java 11. Z garbage collector utför sina cykler i sina trådar. Den pausar programmet i genomsnitt 1 ms. G1- och parallellinsamlarna gör i genomsnitt ungefär 200 ms.

I Java 12 lade Oracle till prestandaförbättringar och klassavlastning även om Z fortfarande har experimentell status. Den är endast tillgänglig på 64-bitars Linux. Men ZGC drar nytta av 64-bitars pekare med en teknik som kallas pekarfärgning. Färgade pekare lagrar extra information om objekt på högen. Detta är en av anledningarna till att den är begränsad till 64-bitars JVM. I den här artikeln har detta scenario förklarats ingående (https://www.opsian.com/blog/javas-new-zgc-is-very-exciting/).

ZGC gör sin markering i tre faser.

1. Kort stop-the-world-fas – Den undersöker GC roots, lokala variabler som pekar på resten av heap. Det totala antalet av dessa rötter är vanligtvis minimalt och skalar inte med belastningens storlek, så ZGC:s pauser är mycket korta och ökar inte när din heap växer.

2. Konkurrentfas – Den går igenom objektgrafen och undersöker de färgade pekarna och markerar tillgängliga objekt. Belastningsbarriären förhindrar konflikter mellan GC-fasen och någon programaktivitet.

3. Omlokaliseringsfasen – Den flyttar levande objekt för att frigöra stora sektioner av heap för att göra allokeringarna snabbare. När omlokaliseringsfasen börjar delar ZGC upp heap:en i sidor och arbetar med en sida i taget. När ZGC är klar med att flytta alla rötter sker resten av omlokaliseringen i en samtidig fas.

ZGC försöker själv ställa in antalet trådar, och det har oftast rätt. Men om ZGC har för många trådar kommer den att svälta ditt program. Om den inte har tillräckligt många kommer du att skapa skräp snabbare än vad GC kan samla in det. ZGC:s faser illustrerar hur den hanterar stora högar utan att påverka prestandan när programminnet växer.

För att aktivera Z Garbage Collector kan vi använda följande argument:

java -XX:+UseZGC -jar Application.java

Shenandoah

Shenandoah är en skräpplockare med ultralåg paustid som minskar GC-paustiderna genom att utföra mer skräpplockningsarbete samtidigt med det pågående Java-programmet. CMS och G1 utför båda samtidig märkning av levande objekt. Shenandoah lägger till samtidig komprimering.

Shenandoah använder minnesregioner för att hantera vilka objekt som inte längre används och vilka som är levande och redo för komprimering. Shenandoah lägger också till en forwarding pointer till varje heap-objekt och använder den för att styra åtkomsten till objektet. Shenandoahs konstruktion byter samtidiga CPU-cykler och utrymme mot förbättringar av paustiden. Forwarding pointern gör det enkelt att flytta objekt, men de aggressiva flyttningarna innebär att Shenandoah använder mer minne och kräver mer parallellt arbete än andra GC:er. Men den gör det extra arbetet med mycket korta stop-the-world-pauser.

Shenandoah bearbetar heapet i många små faser, varav de flesta är samtidiga med programmet. Denna konstruktion gör det möjligt för GC:n att hantera en stor heap på ett effektivt sätt.

  1. Första stop-the-world-pausen i cykeln. Den förbereder högen för samtidig markering och skannar rotuppsättningen. I likhet medZGC motsvarar längden på denna paus storleken på rotmängden, inte högen.
  2. Nästan går en samtidig fas igenom högen och identifierar nåbara och ouppnåeliga objekt.
  3. Den tredje avslutar markeringen genom att tömma väntande uppdateringar i högen och skanna rotmängden på nytt. Denna fas utlöser den andra stopp-till-världen-pausen i cykeln. Antalet väntande uppdateringar och storleken på rotuppsättningen avgör hur lång pausen är.
  4. Därefter kopierar en annan samtidig fas objekten ur de regioner som identifierats i den sista markeringsfasen. Denna process skiljer Shenandoah från andra GC:er eftersom den aggressivt komprimerar högen parallellt med programtrådar.
  5. Nästa fas utlöser den tredje (och kortaste) pausen i cykeln. Den säkerställer att alla GC-trådar har avslutat evakueringen.
  6. När den är klar går en samtidig fas igenom högen och uppdaterar referenser till objekt som flyttats tidigare i cykeln.
  7. Den sista stop-the-world-pausen i cykeln avslutar uppdateringen av referenserna genom att uppdatera rotmängden. Samtidigt återanvänder den de evakuerade regionerna.
  8. Slutligen återtar den sista fasen de evakuerade regionerna, som nu inte har några referenser i dem.

Vi kan konfigurera Shenandoah med en av tre heuristiker. De styr när GC startar sina cykler och hur den väljer regioner för evakuering.

1. Adaptiv: Observerar GC-cyklerna och startar nästa cykel så att den avslutas innan programmet uttömmer heapet. Denna heuristik är standardläget.

2. Statisk: Startar en GC-cykel baserat på hur mycket heap som används och hur hårt allokeringstrycket är.

3. Kompakt: Kör GC-cykler kontinuerligt. Shenandoah startar en ny cykel så snart den föregående avslutas eller baserat på mängden heap-allokering sedan den senaste cykeln. Denna heuristik ger upphov till överbelastning för genomströmning men ger den bästa återvinningen av utrymme.

Shenandoah måste samla in heap snabbare än vad programmet som den betjänar allokerar den. Om allokeringstrycket är för högt och det inte finns tillräckligt med utrymme för nya allokeringar kommer det att uppstå ett fel. Shenandoah har konfigurerbara mekanismer för denna situation.

  • Pacing: Om Shenandoah börjar hamna bakom allokeringstakten kommer den att stoppa allokeringstrådar för att komma ikapp. Stallarna är vanligtvis tillräckliga för milda allokeringstoppar. Shenandoah inför fördröjningar på 10 ms eller mindre. Om pacing misslyckas kommer Shenandoah att gå vidare till nästa steg: degenererad GC.
  • Degenererad GC: Om ett allokeringsfel inträffar startar Shenandoah en stop-the-world-fas. Den använder fasen för att slutföra den aktuella GC-cykeln. Eftersom en stop-the-world inte strider med ansökan om resurser bör cykeln avslutas snabbt och rensa bort tilldelningsbristen. Ofta inträffar en degenererad cykel efter att det mesta av cykelns arbete redan är slutfört, så stop-the-world är kort. GC-loggen kommer dock att rapportera det som en fullständig paus.
  • Full GC: Om både pacing och en degenererad GC misslyckas faller Shenandoah tillbaka till en fullständig GC-cykel. Denna sista GC garanterar att applikationen inte kommer att misslyckas med ett fel som innebär att minnet är slut om det inte finns någon heap kvar.

Shenandoah erbjuder samma fördelar som ZGC med stora heaps men fler inställningsalternativ. Beroende på hur ditt program ser ut kan de olika heuristiken passa bra. Dess paustider är kanske inte lika korta som ZGC:s, men de är mer förutsägbara.

För att aktivera Shenandoah Garbage Collector kan vi använda följande argument:

java -XX:+UseShenanodoahC -jar Application.java

Slutsats

Syftet med den här artikeln är att sammanfatta alla skräpplockare. Därför har vissa delar av innehållet hämtats från de angivna referenserna. Vi måste ha en klar uppfattning om skräpplockarna för att kunna välja en optimal skräpplockare för våra användningsområden. Den optimala garbage collector kommer att förbättra vår applikations prestanda avsevärt.

Referens

  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/

Lämna ett svar

Din e-postadress kommer inte publiceras.