---
id: a5d668f7af98fc92ee33094885d591a3
author: snowmerak
title: Pauza de ceai verde pe care Go runtime-ul o va lua de la tine, GreenTea GC
description: Noul GC GreenTea al Go îmbunătățește performanța prin creșterea eficienței colectării obiectelor mici, pe baza spanurilor de memorie. Vom analiza problemele GC existente și beneficiile GreenTea GC.
language: ro
date: 2025-07-16T11:02:04.831022221Z
path: /blog/posts/greentea-gc:-the-respite-of-a-cup-of-green-tea-seized-by-the-go-compiler-z72acc3f7
category: lowlevel
---

## De ce apare încă un GC nou

### De ce GC-ul existent

Garbage collectorul actual al Go poate fi descris prin următoarele elemente.

- concurrent tri-color mark and sweep
  - Utilizează în total 3 culori (alb, gri, negru) pentru a urmări starea obiectelor.
    - Alb: obiect încă nevizitat
    - Gri: obiect vizitat, dar ale cărui obiecte copil nu au fost toate vizitate
    - Negru: obiect ale cărui obiecte copil au fost toate vizitate
    - La finalul parcurgerii, toate obiectele albe sunt colectate.
  - Utilizează Write Barrier pentru a proteja memoria nou creată în timpul GC-ului.
    - Intervalul în care Write Barrier este activat sau dezactivat reprezintă o parte considerabilă din ceea ce se numește Stop-The-World (denumit în continuare STW).
  - Acest proces este executat în mod concurent.
- No Compaction
  - GC-ul Go nu realizează compactare.
  - Poate apărea fragmentarea memoriei.
    - Totuși, obiectele de până la 32 KB folosesc cache-ul per-P al alocatorului de memorie (Allocator) al limbajului Go pentru a minimiza fragmentarea.
- Non-Generational
  - GC-ul Go nu gestionează obiectele pe generații.
  - Toate obiectele aparțin aceleiași generații.
- Escape Analysis
  - Go utilizează Escape Analysis pentru a determina dacă un obiect este alocat în heap sau în stack.
  - În linii mari, dacă există dangling pointers sau se utilizează interfețe, se poate considera că obiectul este alocat în heap.

### Lucrul important

GC-ul Go parcurge toate obiectele pornind de la rădăcini și execută marcarea tri-color. Dacă acest proces ar trebui descris într-un singur rând, s-ar putea spune că este un `algoritm de parcurgere concurentă a unui graf de sortare topologică`. Totuși, fiecare obiect se află, cu probabilitate mare, în regiuni diferite de memorie. Pe scurt:

1. Să presupunem că există două regiuni de memorie aflate la aproximativ 32 MB distanță una de cealaltă.
2. În fiecare dintre aceste regiuni de memorie sunt alocate câte 5 obiecte.
   1. Obiectele A, B, C se află în regiunea 1
   2. Obiectele D, E se află în regiunea 2
3. Ordinea referințelor între obiecte este `A -> D -> B -> E -> C`.
4. Când începe GC-ul, se vizitează A, apoi D, apoi B, apoi E și apoi C.
5. În acest caz, deoarece A și D se află în regiuni de memorie diferite, la vizitarea lui D după A trebuie să se treacă de la o regiune de memorie la alta.
6. În acest proces apare așa-numitul cost de salt în memorie (memory jump), care implică trecerea între regiuni de memorie și umplerea de noi linii de cache. O parte considerabilă a timpului CPU al aplicației poate fi alocată acestor operațiuni GC.
7. Acest cost apare continuu pe durata desfășurării GC-ului.

### Care este problema?

Comportamentul acestui GC devine problematic în următoarele cazuri.

- Când numărul de nuclee este mare și memoria este mare
  - GC-ul Go rulează, în mod implicit, concurent.
  - Dar, dacă regiunea de memorie este întinsă și obiectele sunt distribuite, mai multe nuclee parcurg simultan obiecte din spații de memorie diferite.
  - În acest proces, dacă magistrala dintre CPU și memorie nu este suficient de largă, lățimea de bandă a memoriei poate deveni un blocaj.
  - De asemenea, deoarece există distanță fizică reală, fiecare parcurgere poate introduce o întârziere relativ mare.
- Când există multe obiecte mici
  - Dacă folosiți în Go arbori sau grafuri cu adâncime mare sau cu mulți descendenți, GC-ul trebuie să parcurgă toate aceste obiecte.
  - În acest proces, dacă obiectele sunt distribuite în regiuni diferite de memorie, întârzierea apare din primul motiv.
  - De asemenea, dacă există multe obiecte mici, GC-ul trebuie să le parcurgă pe toate, astfel încât, pe durata GC-ului, nucleele CPU vor aloca o cantitate considerabilă de resurse și vor efectua muncă pentru GC.

Pentru a rezolva aceste probleme, echipa Golang a prezentat GreenTea GC.

## Nu mai aveți timp pentru încă o pauză de ceai verde

### Ce răpește ceaiul verde

Din punctul de vedere al soluției celei mai rapide pentru GC-ul existent, zona aplicabilă pare a fi localitatea memoriei. Adică, plasarea obiectelor apropiate unele de altele pentru a minimiza saltul între regiuni de memorie. Totuși, nu se poate impune un anumit tipar de scriere a codului programatorilor și, de asemenea, alocarea obiectelor nu poate fi prevăzută, în funcție de fluxul de lucru.

Probabil din acest motiv, metoda aleasă de echipa Golang este **Memory Span**.

### Ce este Memory Span?

Memory Span este o zonă în care se alocă o regiune de memorie relativ mare și în care se plasează obiecte mici. Iar noul GC denumit GreenTea GC efectuează colectarea de gunoi asupra acestor memory span-uri. Detaliile de funcționare sunt aproape identice cu cele ale tradiționalului Tri-Color Mark and Sweep.

### Funcționarea GreenTea GC

Mai întâi, GreenTea GC alocă un memory span. Dimensiunea sa, conform descrierii anterioare, este de 8 KiB, o dimensiune considerabilă. În interiorul acestuia pot fi alocate obiecte de cel mult 512 bytes. Dimensiunea nodurilor din exemplul cu arbori sau grafuri sau a structurilor care migrează în mod obișnuit în heap este greu de imaginat ca fiind mai mare decât această valoare. Obiectele de 512 bytes sau mai puțin se acumulează în acest memory span de fiecare dată când migrează în heap, iar când acest memory span se umple, se alocă un nou memory span.

Acum, când are loc un GC, GreenTea GC pune aceste memory span-uri într-o coadă și le verifică secvențial. În acest proces, GreenTea GC utilizează o planificare aproape similară modelului GMP existent. Mecanismele precum work stealing sunt de asemenea implementate. Oricum, worker-ul care extrage un memory span din coadă verifică obiectele din interiorul memory span-ului care i-a fost atribuit. În acest proces, se utilizează în mod identic Tri-Color Mark and Sweep.

### Ce avantaj aduce?

În acest proces, diferența față de GC-ul existent se reduce, în esență, la un singur aspect. Unitatea în care se execută GC-ul la un moment dat nu mai este **obiectul**, ci **memory span-ul**. Acest lucru conferă GC-ului următoarele avantaje:

- Localitatea memoriei: deoarece obiectele sunt grupate în memory span, saltul de memorie la parcurgerea obiectelor este minimizat. Adică, cache-ul CPU poate fi utilizat în cea mai mare măsură.
- Îmbunătățirea performanței GC: prin executarea GC-ului la nivel de memory span, GC-ul funcționează mai eficient într-un mediu multi-core.
- Optimizarea alocării memoriei: deoarece memory span-urile sunt alocate cu dimensiune fixă, supraîncărcarea alocării obiectelor mici se reduce și scade probabilitatea apariției fragmentării. Acest lucru crește eficiența eliberării memoriei alocate.

Pe scurt, de acum înainte putem aloca obiecte de până la 512 bytes mai des și cu mai multă ușurință.

Totuși, există și aici anumite cazuri favorabile.

- Structuri de tip arbore/graf: cu fan-out ridicat și care se modifică rar
  - B+ tree, Trie, AST (Abstract Syntax Tree)
  - Structuri de date prietenoase cu cache-ul
- Procesare în loturi: fluxuri de lucru cu alocare masivă de obiecte mici
  - Multe obiecte mici generate prin parsarea JSON
  - Obiecte DAO din seturi de rezultate ale bazelor de date

În aceste cazuri, GreenTea GC poate oferi performanțe mai bune decât GC-ul existent. Totuși, nu se aplică în toate situațiile, iar mai ales când obiectele sunt distribuite în regiuni diferite de memorie, nu se poate aștepta încă o îmbunătățire dramatică a performanței.

## Deci

Echipa Golang intenționează probabil să continue îmbunătățirea GC-ului pe termen lung. GreenTea GC poate fi considerat o modificare minoră la scară mică și nu înlocuiește GC-ul existent. Totuși, GreenTea GC pare un caz interesant care oferă o imagine asupra problemelor cu care se confruntă sau pe care le anticipează echipa Golang. Este o problemă surprinzător de complexă, dar tentativa de a o rezolva prin adăugarea unui concept relativ simplu a fost, de asemenea, impresionantă. Personal, consider că este un caz interesant.

GreenTea GC este o funcționalitate experimentală introdusă începând cu Go 1.25. Poate fi activată prin setarea variabilei de mediu `GOEXPERIMENT=greenteagc`. Deoarece această funcționalitate este încă experimentală, este necesară testarea amănunțită înainte de utilizarea acesteia în medii de producție.

## Referințe

- [github.com/golang/go - runtime: green tea garbage collector #73581](https://github.com/golang/go/issues/73581)
