GreenTea GC: Go Runtime, ktorý vám ukradne chvíľu pokoja pri šálke zeleného čaju
Prečo vzniká ďalší nový GC?
Prečo existujúci GC?
Súčasný Go GC možno opísať nasledovne:
- concurrent tri-color mark and sweep
- Na sledovanie stavu objektov sa používajú tri farby (biela, sivá, čierna).
- Biela: objekty, ktoré ešte neboli navštívené
- Sivá: objekty, ktoré boli navštívené, ale ktorých všetky podradené objekty ešte neboli navštívené
- Čierna: objekty, ktorých všetky podradené objekty boli navštívené
- Po dokončení iterácie sa zozbierajú všetky biele objekty.
- Na ochranu novo vytvorenej pamäte počas GC sa používa Write Barrier.
- Čas zapnutia/vypnutia Write Barrier tvorí značnú časť takzvaného Stop-The-World (ďalej len STW).
- Tento proces sa vykonáva súbežne.
- Na sledovanie stavu objektov sa používajú tri farby (biela, sivá, čierna).
- No Compaction
- Go GC nevykonáva komprimáciu.
- Môže dôjsť k fragmentácii pamäte.
- Avšak objekty menšie ako 32 kb minimalizujú fragmentáciu využitím per-P cache alokátora pamäte (Allocator) jazyka Go.
- Non-Generational
- Go GC nespravuje objekty podľa generácií.
- Všetky objekty patria do rovnakej generácie.
- Escape Analysis
- Go určuje, či sa objekt alokuje na heap alebo na stack, prostredníctvom Escape Analysis.
- Približne platí, že ak sa používajú dangling pointers alebo rozhrania, objekt sa alokuje na heap.
Dôležitý aspekt
Go GC preskúmava všetky objekty z koreňa a vykonáva trojfarebné značenie. Tento proces možno v jednej vete opísať ako algoritmus súbežného prehľadávania grafu s topologickým triedením
. Avšak každý objekt sa s vysokou pravdepodobnosťou nachádza v inej oblasti pamäte. Konkrétne,
- Predpokladajme, že existujú dve oblasti pamäte vzdialené približne 32 MB.
- V každej z týchto dvoch oblastí pamäte je alokovaných 5 objektov.
- Objekty A, B, C sú v oblasti 1.
- Objekty D, E sú v oblasti 2.
- Poradie referencií objektov je
A -> D -> B -> E -> C
. - Keď sa spustí GC, navštívi A, potom D, potom B, potom E a nakoniec C.
- V tomto prípade, keďže A a D sa nachádzajú v rôznych oblastiach pamäte, pri prechode z A na D je potrebné presunúť sa medzi oblasťami pamäte.
- Tento proces zahŕňa presun medzi oblasťami pamäte a vyplnenie nových cache liniek, čo vedie k takzvaným nákladom na skok v pamäti. Značná časť CPU času, ktorý aplikácia využíva, môže byť pridelená týmto GC operáciám.
- Tieto náklady vznikajú neustále počas vykonávania GC.
Takže v čom je problém?
Takéto správanie GC je obzvlášť nevýhodné v nasledujúcich prípadoch:
- Veľký počet jadier a veľká pamäť
- Go GC sa v zásade vykonáva súbežne.
- Ak je však oblasť pamäte rozsiahla a objekty sú rozptýlené, viaceré jadrá budú súbežne prehľadávať objekty v rôznych pamäťových priestoroch.
- Ak zbernica medzi CPU a pamäťou nie je dostatočne široká, priepustnosť pamäte sa môže stať prekážkou.
- Navyše, keďže sú fyzicky vzdialené, každé prehľadávanie bude znamenať relatívne veľké oneskorenie.
- Mnoho drobných objektov
- Ak spravujete stromy alebo grafy s hlbokou hĺbkou alebo mnohými potomkami v Go, GC musí prehľadať všetky tieto objekty.
- Ak sú objekty rozptýlené v rôznych pamäťových oblastiach, z dôvodu uvedeného v prvom bode dôjde k oneskoreniu.
- Okrem toho, ak je mnoho drobných objektov, GC musí prehľadať všetky tieto objekty, a preto počas vykonávania GC značná časť kapacity CPU bude pridelená a pracovať pre GC.
Na vyriešenie týchto problémov tím Golang predstavil GreenTea GC.
Už si nemôžete dovoliť piť viac zeleného čaju.
Čo vám berie zelený čaj?
Najrýchlejšie riešenie existujúceho GC sa javí ako oblasť lokality pamäte. To znamená minimalizovať skoky v pamäti umiestnením objektov blízko seba. Avšak nie je možné vynútiť si vzorce správania programátora pri písaní kódu a alokácia objektov je nepredvídateľná v závislosti od pracovného postupu.
Preto si tím Golang vybral metódu Memory Span.
Čo je Memory Span?
Memory Span je oblasť, kde sa alokuje relatívne veľká pamäťová oblasť na alokáciu malých objektov. A nový GC s názvom GreenTea GC vykonáva zber odpadu pre túto oblasť Memory Span. Detailná operácia je takmer identická s existujúcim Tri-Color Mark and Sweep.
Fungovanie GreenTea GC
Najprv GreenTea GC alokuje pamäťový blok (Memory Span). Jeho veľkosť je, ako už bolo spomenuté, 8 KiB, čo je dostatočne veľká hodnota. A v rámci tohto bloku je možné alokovať objekty s maximálnou veľkosťou 512 bytov. To je približne veľkosť uzlov stromov alebo grafov, ktoré boli uvedené ako príklady, alebo veľkosť bežných štruktúr, ktoré "unikajú" na heap, takže je ťažké, aby boli väčšie. Objekty menšie ako 512 bytov sa pri každom "úniku" na heap ukladajú do tohto pamäťového bloku, a keď sa tento pamäťový blok zaplní, alokuje sa nový pamäťový blok.
Keď dôjde k GC, GreenTea GC vloží tieto pamäťové rozsahy do fronty a kontroluje ich postupne. V tomto procese GreenTea GC používa plánovanie, ktoré je takmer identické s existujúcim modelom GMP. Implementované sú aj oblasti ako kradnutie úloh. V každom prípade, pracovník, ktorý vyberie pamäťový rozsah z fronty, kontroluje vnútorné objekty pamäťového rozsahu, ktorý mu bol pridelený. V tomto procese sa rovnako používa Tri-Color Mark and Sweep.
Aké sú výhody?
Hlavný rozdiel medzi týmto procesom a existujúcim GC je len jeden. Jednotka, v ktorej sa GC vykonáva naraz, sa zmenila z objektu na pamäťový rozsah (Memory Span). Vďaka tomu má GC nasledujúce výhody:
- Lokalita pamäte: Keďže sú objekty zhromaždené v pamäťových rozsahoch, minimalizuje sa skákanie v pamäti pri prehľadávaní objektov. To znamená, že sa maximálne využíva CPU cache.
- Zlepšenie výkonu GC: Vykonávaním GC na úrovni pamäťových rozsahov pracuje GC efektívnejšie v prostredí s viacerými jadrami.
- Optimalizácia alokácie pamäte: Pamäťové rozsahy sú alokované s pevnou veľkosťou, čo znižuje režijné náklady na alokáciu pamäte pri alokácii malých objektov a znižuje pravdepodobnosť fragmentácie. To zvyšuje efektivitu uvoľňovania pamäte.
Stručne povedané, odteraz môžeme alokovať objekty s veľkosťou menšou ako 512 bajtov častejšie a s ľahším srdcom.
Je však potrebné poznamenať, že aj tu existujú určité výhodné scenáre.
- Stromové/grafové štruktúry: Ak je fan-out vysoký a zmeny sa nevyskytujú často.
- B+ stromy, Trie, AST (Abstract Syntax Tree)
- Dátové štruktúry priateľské ku cache
- Dávkové spracovanie: Pracovné postupy s hromadnou alokáciou malých dát
- Viacero malých objektov vytvorených parsovaním JSON
- DAO objekty z výsledkov databázy
V takýchto prípadoch môže GreenTea GC dosiahnuť lepší výkon ako existujúci GC. Avšak neplatí to vo všetkých prípadoch, a najmä ak sú objekty rozptýlené v rôznych pamäťových oblastiach, stále je ťažké očakávať dramatické zlepšenie výkonu.
A tak
Zdá sa, že tím Golang má v úmysle dlhodobo pokračovať v zlepšovaní GC. Tento GreenTea GC možno považovať za menšiu zmenu v malej oblasti a nenahrádza existujúci GC. Avšak GreenTea GC sa javí ako zaujímavý prípad, ktorý naznačuje problémy, ktorým tím Golang čelí alebo ktoré predpokladá. Bolo tiež pôsobivé, že sa pokúsili vyriešiť prekvapivo zložitý problém relatívne jednoduchým pridaním konceptu. Osobne to považujem za zaujímavý prípad.
GreenTea GC je experimentálna funkcia, ktorá bude predstavená v Go 1.25. Môže byť aktivovaná pomocou premennej prostredia GOEXPERIMENT=greenteagc
. Táto funkcia je stále experimentálna, a preto je potrebné dôkladné testovanie pred jej použitím v produkčnom prostredí.