Detaljno objašnjenje klasičnih Java sakupljača smeća
- Propusnost (throughput): udeo vremena rada programa u ukupnom vremenu izvršavanja (ukupno vreme = vreme rada programa + vreme sakupljanja smeća); što je vreme sakupljanja smeća kraće, propusnost je veća;
- Vreme pauze (pause time): trajanje STW-a;
- Zauzeće memorije: veličina koju zauzima Java heap.
Ove tri tačke čine nemogući trougao, odnosno jedan sakupljač smeća ne može istovremeno da zadovolji sve tri. Sa porastom hardverskih mogućnosti, zauzeće memorije više nije žarište; prilikom ocene performansi sakupljača smeća fokus je na propusnosti i vremenu pauze. Propusnost i vreme pauze su u međusobnom sukobu, a trenutno težimo sledećem: uz maksimalnu propusnost, smanjiti vreme pauze.
Istorija razvoja sakupljača smeća
- godine, uz JDK 1.3.1, objavljen je prvi serijski Serial GC; ParNew sakupljač smeća jeste višenitna verzija Serial sakupljača;
- februara 2002, Parallel GC i Concurrent Mark Sweep GC (CMS) objavljeni su uz JDK 1.4.2;
- Od JDK-a 1.6 Parallel GC postaje podrazumevani GC za HotSpot;
- godine, u verziji JDK 1.7u4, G1 postaje dostupan;
- godine, u JDK-u 9, G1 postaje podrazumevani sakupljač smeća, a CMS se označava kao zastareo;
- Marta 2018, u JDK-u 10 poboljšana je paralelnost G1;
- Septembra 2018, JDK 11 uvodi Epsilon sakupljač smeća i istovremeno ZGC (eksperimentalna verzija);
- Marta 2019, JDK 12 izlazi, poboljšava G1 i uvodi Shenandoah GC (eksperimentalna verzija);
- Septembra 2019, JDK 13 izlazi, poboljšava ZGC;
- Marta 2020, JDK 14 izlazi, uklanja CMS i proširuje primenu ZGC na MAC i Windows.
Kombinacije sakupljača smeća
Veze između 7 klasičnih sakupljača smeća:

Objašnjenje:
- Ako između dva sakupljača postoji veza, to znači da se mogu koristiti zajedno;
- Serial Old služi kao rezervna varijanta za CMS u slučaju „Concurrent Mode Failure“;
- G1 se može koristiti i za mladu i za staru generaciju;
- Crvena isprekidana linija: JDK 8 proglašava ove dve kombinacije zastarelim, a u JDK-u 9 su potpuno uklonjene;
- Zelena isprekidana linija: u JDK-u 14 ova kombinacija je napuštena;
- Zelena isprekidana ivica: u JDK-u 14 CMS je uklonjen.
Pregled podrazumevanog sakupljača smeća
Napišimo jednostavan Java program:
public class Test {
public static void main(String[] args) {
System.out.println("hello");
}
}Dodaj parametar JVM-a -XX:+PrintCommandLineFlags; u okruženju JDK 8 program ispisuje:
-XX:InitialHeapSize=536870912 -XX:MaxHeapSize=8589934592 -XX:+PrintCommandLineFlags -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseParallelGC
hello-XX:+UseParallelGC pokazuje da je podrazumevani sakupljač smeća u JDK-u 8 Parallel.
U okruženju JDK 9 ispisuje:
-XX:G1ConcRefinementThreads=10 -XX:InitialHeapSize=536870912 -XX:MaxHeapSize=8589934592 -XX:+PrintCommandLineFlags -XX:ReservedCodeCacheSize=251658240 -XX:+SegmentedCodeCache -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseG1GC
hello-XX:+UseG1GC pokazuje da je podrazumevani sakupljač smeća u JDK-u 9 G1.
Uvod u klasične sakupljače smeća
Sakupljači Serial i Serial Old
Serial sakupljač smeća jeste jednonitni serijski sakupljač, podrazumevani sakupljač smeća za mladu generaciju u Client režimu HotSpot-a; koristi algoritam kopiranja, serijsko sakupljanje i STW mehanizam pri oslobađanju memorije.
Serial Old sakupljač smeća, koji Serial pruža za staru generaciju, koristi algoritam označavanja-sabijanja, serijsko sakupljanje i STW mehanizam pri oslobađanju memorije:
- Serial Old je podrazumevani sakupljač smeća za staru generaciju u Client režimu;
- Serial Old u Server režimu ima uglavnom dve svrhe: da radi zajedno sa Parallel Scavenge za mladu generaciju; i da bude rezervno rešenje za CMS sakupljač stare generacije.
Serial je pogodan za virtuelnu mašinu koja radi u Client režimu ili za okruženja sa malo memorije (od nekoliko desetina MB do jedne-dve stotine MB). Pošto je serijski, ima duže STW pauze, pa nije pogodan za aplikacije koje zahtevaju brz odziv i snažnu interaktivnost.
Parametrom XX:+UseSerialGC može se uključiti Serial sakupljač, što znači da mlada generacija koristi Serial, a stara Serial Old.
Sakupljač ParNew
ParNew je skraćenica od Parallel New, višenitna verzija Serial sakupljača smeća. ParNew je podrazumevani sakupljač smeća za mladu generaciju mnogih JVM-ova koji rade u Server režimu; koristi algoritam kopiranja, paralelno sakupljanje i STW mehanizam pri oslobađanju memorije.
Parametrom XX:+UseParNewGC može se uključiti ParNew sakupljač, što znači da mlada generacija koristi ParNew, dok stara generacija ostaje netaknuta.
Šema kombinacije Serial i ParNew sa Serial Old sakupljačem:
Sakupljači Parallel i Parallel Old
Parallel Scavenge sakupljač smeća takođe deluje na mladu generaciju, isto koristi algoritam kopiranja, paralelno sakupljanje i STW mehanizam.
Poređenje Parallel Scavenge i ParNew:
- Parallel Scavenge je sakupljač smeća orijentisan ka propusnosti;
- Parallel Scavenge ima strategiju adaptivnog podešavanja.
JDK 1.6 pruža paralelni sakupljač smeća za staru generaciju — Parallel Old, koji zamenjuje Serial Old. Parallel koristi algoritam označavanja-sabijanja, paralelno sakupljanje i STW mehanizam.
Parametrom -XX:+UseParallelGC određuje se da mlada generacija koristi Parallel Scavenge sakupljač; -XX:+UseParallelOldGC da stara generacija koristi Parallel Old sakupljač; oni idu u paru, uključivanjem jednog uključuje se i drugi.
Pored toga, parametrom -XX:ParallelGCThreads= može se podesiti broj niti paralelnog sakupljača:
- Podrazumevano, kada je broj CPU-ova manji od 8, vrednost
-XX:ParallelGCThreads=jednaka je broju CPU-ova; - Kada je broj CPU-ova veći od 8, vrednost
-XX:ParallelGCThreads=jednaka je3+5*CPU_COUNT/8.
-XX:+UseAdaptiveSizePolicy uključuje strategiju adaptivnog podešavanja za Parallel Scavenge:
- U ovom režimu veličina mlade generacije, odnos između oblasti eden i oblasti preživelih, kao i prag starosti objekata koji prelaze u staru generaciju, automatski se podešavaju kako bi se pronašla ravnoteža između veličine heap-a, propusnosti i vremena pauze.
Sakupljač CMS
U JDK-u 1.5 HotSpot je predstavio prvi pravi konkurentni sakupljač — CMS (Concurrent-Mark-Sweep), koji je prvi put omogućio da nit za sakupljanje smeća i korisničke niti rade istovremeno. CMS je usmeren na to da vreme pauze korisničkih niti prilikom sakupljanja smeća bude što kraće.
Kao sakupljač smeća za staru generaciju, CMS se ne može koristiti u kombinaciji sa Parallel Scavenge sakupljačem za mladu generaciju, već samo sa ParNew ili Serial.
Šema CMS sakupljača:
Glavno je podeljeno u sledeće korake:
- Inicijalno označavanje (Initial-Mark): sve korisničke niti se pauziraju (STW); ova faza samo označava objekte na koje GC Roots mogu direktno da se vežu, pa je vrlo brza i STW kratak;
- Konkurentno označavanje (Concurrent-Mark): u ovoj fazi polazeći od objekata direktno povezanih sa GC Roots obilazi se cela mreža objekata; iako ovaj proces traje duže, ne zahteva pauziranje korisničkih niti — izvršava se konkurentno, bez STW;
- Ponovno označavanje (Remark): pošto se korisničke niti i u prethodnom koraku izvršavaju, ovaj korak služi da ispravi zapise o označavanju onog dela objekata čije se označavanje promenilo zbog nastavljenog rada korisničkih niti; ova faza traje nešto duže od inicijalnog označavanja, ali znatno kraće od konkurentnog označavanja;
- Konkurentno brisanje (Concurrent-Sweep): ova faza čisti i briše smeće i oslobađa prostor. Pošto se objekti ne pomeraju, u ovoj fazi takođe nema STW.
CMS ima i očigledne prednosti i mane:
Prednosti:
- Konkurentno sakupljanje;
- Niska latencija.
Mane:
- Stvara fragmente. Pošto se u fazi čišćenja korisničke niti i dalje izvršavaju, može se koristiti samo algoritam označavanja-brisanja koji ne pomera objekte, a taj algoritam vodi problemu fragmentacije;
- Osetljiv na CPU resurse. CPU resursi, pored korisničkih niti, moraju se delimično angažovati i za sakupljanje smeća, što smanjuje propusnost;
- Ne može da obradi plutajuće smeće. U fazi konkurentnog označavanja korisničke niti se ne zaustavljaju, pa i tada nastaje smeće — CMS ga ne može označiti, već se ono obrađuje tek pri sledećem GC-ju.
Pored toga, tokom CMS sakupljanja, pošto se korisničke niti ne prekidaju, mora se osigurati da korisničke niti imaju dovoljno memorije na raspolaganju. Drugim rečima, CMS sakupljač ne može čekati da stara generacija bude skoro puna da bi sakupljao, već treba da započne sakupljanje kada zauzeće heap memorije dostigne određeni prag. Ako CMS tokom rada ostane bez rezervisane memorije, javlja se „Concurrent Mode Failure“; virtuelna mašina tada pokreće rezervnu varijantu i privremeno angažuje Serial Old sakupljač da završi sakupljanje smeća u staroj generaciji.
Parametri koje moguće podesiti za CMS sakupljač:
-XX:+UseConcMarkSweepGC, uključuje CMS GC; kada se uključi,-XX:+UseParNewGCse automatski uključuje;-XX:CMSInitiatingOccupanyFraction=, podešava prag zauzeća heap memorije; kada se dostigne taj prag, CMS započinje sakupljanje (u JDK-u 5 i ranijim podrazumevana vrednost je 68, a od JDK-a 6 nadalje 92%);-XX:+UseCMSCompactAtFullCollection, određuje da se nakon što CMS sakupi staru generaciju izvrši sabijanje memorijskog prostora kako bi se izbegla fragmentacija;-XX:CMSFullGCsBeforeCompaction, podešava nakon koliko CMS GC-ova se vrši sabijanje memorijskog prostora;-XX:ParallelCMSThreads=, podešava broj CMS niti. Podrazumevani broj pokrenutih niti je(ParallelGCThreads+3)/4. Znamo da kada je broj CPU-ova manji od 8, podrazumevana vrednost ParallelGCThreads iznosi broj CPU-ova, pa za 8-jezgrani CPU podrazumevani broj CMS niti iznosi 3 — drugim rečima, samo 62,5% CPU resursa ide korisničkim nitima. Zbog toga CMS nije pogodan za scenarije koji zahtevaju visoku propusnost.
Sakupljač G1
G1 (Garbage First) sakupljač deli heap memoriju na mnogo međusobno nezavisnih oblasti (region, fizički nepovezanih), pa različite oblasti predstavljaju oblast eden, oblast preživelih i staru generaciju.
G1 izbegava sakupljanje smeća nad celim Java heap-om; on prati vrednost sakupljanja smeća u svakom regionu (veličina prostora koji se dobija i iskustvena vrednost potrebnog vremena) i u pozadini održava listu po prioritetu; svaki put, u skladu sa dozvoljenim vremenom sakupljanja, prvo sakuplja regione najveće vrednosti.
Objašnjenje regiona

Slika je preuzeta sa tech.meituan.com/2016/09/23/…
- E označava oblast eden, S oblast preživelih, O staru generaciju, a prazno neiskorišćenu memorijsku oblast;
- Jedan region u istom trenutku može imati samo jednu ulogu;
- G1 uvodi potpuno novu memorijsku oblast — Humongous, koja služi prvenstveno za čuvanje velikih objekata.
Proces sakupljanja smeća kod G1 prikazan je na sledećem dijagramu:
Glavno je podeljeno u sledeće korake:
- Inicijalno označavanje: samo se označavaju objekti na koje se GC Roots direktno vezuju; potrebno je STW, ali je ovaj proces vrlo brz;
- Konkurentno označavanje: polazeći od GC Roots vrši se analiza dostupnosti objekata u heap-u i pronalaze živi objekti; ova faza traje duže, ali se može izvršavati konkurentno sa korisničkim nitima;
- Konačno označavanje: uglavnom ispravlja zapise o označavanju onog dela objekata čije se označavanje promenilo u fazi konkurentnog označavanja zbog nastavljenog rada korisničkih niti; potrebno je STW;
- Selektivno sakupljanje: regioni se ređaju po vrednosti i ceni sakupljanja, pa se na osnovu korisnikom željenog vremena pauze sastavlja plan sakupljanja. U ovoj fazi se korisničke niti pauziraju (STW).
Prednosti i mane G1 sakupljača:
Prednosti:
- Paralelnost i konkurentnost;
- Sakupljanje po generacijama, pa se za različite objekte mogu koristiti različiti algoritmi;
- Prostorna celovitost — algoritam označavanja-sabijanja znači da nema fragmentacije memorije;
- Predvidljivo vreme pauze: korisnik može jasno navesti da u vremenskom isečku od M milisekundi vreme potrošeno na sakupljanje smeća ne prelazi N milisekundi (na osnovu liste prioriteta prvo se sakupljaju regioni najveće vrednosti).
Mane:
- U okruženjima sa malo memorije nema prednost u odnosu na CMS; G1 je namenjen velikim heap memorijama;
- Tokom rada korisničkog programa, G1, bilo u pogledu zauzeća memorije radi sakupljanja smeća ili dodatnog opterećenja pri radu programa, ima veće troškove od CMS-a.
Relevantni parametri G1 sakupljača:
-XX:+UseG1GC, uključuje G1 GC;-XX:G1HeapRegionSize=, podešava veličinu regiona. Vrednost je stepen dvojke, u rasponu od 1 MB do 32 MB, sa ciljem da se prema najmanjoj veličini heap-a izdvoji oko 2048 regiona. Prema tome, ako se vrednost postavi na 2 MB, najmanja memorija heap-a iznosi oko 4 GB;-XX:MaxGCPauseMillis=, podešava željeni maksimalni indikator trajanja GC pauze (JVM će se potruditi da ga ostvari, ali ne garantuje); podrazumevana vrednost je 200 ms;-XX:ParallelGCThread=, podešava broj GC niti tokom STW-a, najviše do 8;-XX:ConcGCThreads=, podešava broj niti za konkurentno označavanje; preporučena vrednost iznosi oko 1/4 vrednosti ParallelGCThread;-XX:InitiatingHeapOccupancyPercent=, podešava prag zauzeća Java heap-a koji pokreće konkurentni GC ciklus; kada se pređe ta vrednost, pokreće se GC; podrazumevano 45.
Rezime
Gornji klasični sakupljači smeća svaki ima svoje osobine; pri konkretnoj upotrebi treba birati različite sakupljače prema konkretnoj situaciji:

| Sakupljač smeća | Kategorija | Lokacija dejstva | Algoritam | Karakteristika | Scenarij primene |
|---|---|---|---|---|---|
| Serial | Serijski | Mlada generacija | Algoritam kopiranja | Prvenstvo brzine odziva | Client režim u okruženju sa jednim CPU-om |
| ParNew | Paralelni | Mlada generacija | Algoritam kopiranja | Prvenstvo brzine odziva | Server režim sa više CPU-ova, u paru sa CMS |
| Parallel | Paralelni | Mlada generacija | Algoritam kopiranja | Prvenstvo propusnosti | Pozadinska izračunavanja bez mnogo interakcije |
| Serial Old | Serijski | Stara generacija | Algoritam označavanja-sabijanja | Prvenstvo brzine odziva | Client režim u okruženju sa jednim CPU-om |
| Parallel Old | Paralelni | Stara generacija | Algoritam označavanja-sabijanja | Prvenstvo propusnosti | Pozadinska izračunavanja bez mnogo interakcije |
| CMS | Konkurentni | Stara generacija | Algoritam označavanja-sabijanja | Prvenstvo brzine odziva | Internet ili B/S biznis |
| G1 | Paralelni i konkurentni | Mlada i stara generacija | Algoritam kopiranja, algoritam označavanja-sabijanja | Prvenstvo brzine odziva | Serverke aplikacije |
Novi sakupljači smeća
Epsilon sakupljač, Shenandoah sakupljač, ZGC sakupljač
Referenca: https://juejin.cn/post/7029155686575521828, priredio: Erge
