---
id: a5d668f7af98fc92ee33094885d591a3
author: snowmerak
title: Go çalışma zamanının elinden alamayacağı bir fincan yeşil çayın huzuru, GreenTea GC
description: Go'nun yeni GreenTea GC'si, bellek span'larına dayalı yaklaşımıyla küçük nesne çöp toplama verimliliğini artırarak performansı iyileştirir. Mevcut GC sorunları ile GreenTea GC'nin sağladığı avantajlar incelenmektedir.
language: tr
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
---

## Yeni Bir GC Neden Daha Çıkıyor

### Mevcut GC Neden Var

Go'nun mevcut GC'si aşağıdaki ifadelerle açıklanabilir.

- concurrent tri-color mark and sweep
  - Nesnelerin durumunu izlemek için toplam 3 renk (beyaz, gri, siyah) kullanır.
    - Beyaz: Henüz ziyaret edilmemiş nesne
    - Gri: Ziyaret edilmiş ancak tüm alt nesneleri henüz ziyaret edilmemiş nesne
    - Siyah: Tüm alt nesneleri ziyaret edilmiş nesne
    - Gezinme tamamlandıktan sonra beyaz nesnelerin tümü toplanır.
  - GC sırasında yeni oluşturulan belleği korumak için Write Barrier kullanır.
    - Write Barrier'ın açılıp kapatılma süresi, yaygın olarak bahsedilen Stop-The-World (bundan sonra STW) süresinin önemli bir kısmını oluşturur.
  - Bu süreç eşzamanlı olarak yürütülür.
- No Compaction
  - Go'nun GC'si compaction (sıkıştırma) yapmaz.
  - Bellek parçalanması (fragmentation) meydana gelebilir.
    - Ancak 32KB altındaki nesneler için Go dilinin bellek ayırıcısının (Allocator) per-P önbelleği kullanılarak parçalanma en aza indirilir.
- Non-Generational
  - Go'nun GC'si nesneleri kuşaklara (generation) göre yönetmez.
  - Tüm nesneler aynı kuşağa aittir.
- Escape Analysis
  - Go, Escape Analysis aracılığıyla bir nesnenin heap'e mi yoksa stack'e mi ayrılacağına karar verir.
  - Kabaca söylemek gerekirse, dangling pointer kullanılıyorsa veya interface kullanılıyorsa nesnenin heap'e ayrıldığı düşünülebilir.

### Önemli Olan Nokta

Go'nun GC'si, tüm nesneleri kökten (root) başlayarak dolaşır ve tri-color mark işlemini gerçekleştirir. Bu süreci tek satırda ifade etmek gerekirse `topolojik sıralama tabanlı graf eşzamanlı gezinme algoritması` denilebilir. Ancak her nesne büyük olasılıkla farklı bellek bölgelerinde bulunur. Açıkça söylemek gerekirse:

1. Birbirinden yaklaşık 32MB uzaklıkta iki bellek bölgesi olduğunu varsayalım.
2. Bu iki bellek bölgesinin her birinde 5 nesne tahsis edilmiştir.
   1. A, B, C nesneleri 1. bölgededir.
   2. D, E nesneleri 2. bölgededir.
3. Nesnelerin referans sırası `A -> D -> B -> E -> C` şeklindedir.
4. GC başladığında A ziyaret edilir, ardından D, B, E ve C sırayla ziyaret edilir.
5. Bu noktada A ve D farklı bellek bölgelerinde bulunduğundan, A'yı ziyaret edip D'yi ziyaret etme sürecinde bellek bölgesi değiştirilmek zorundadır.
6. Bu süreçte bellek bölgesi değişimi ve yeni cache line'ların doldurulması gibi, yaygın olarak bilinen bellek atlama (memory jump) maliyeti oluşur. Uygulamanın kullandığı CPU süresinin önemli bir kısmı bu GC işlemlerine ayrılabilir.
7. Bu maliyet GC devam ettiği sürece sürekli oluşur.

### Peki Sorun Ne?

GC'nin bu davranışı şu durumlarda ciddi bir sorun teşkil eder:

- Çekirdek sayısının fazla olduğu ve belleğin büyük olduğu durumlar
  - Go'nun GC'si varsayılan olarak eşzamanlı çalışır.
  - Ancak bellek bölgesi geniş ve nesneler dağınık olduğunda, birden fazla çekirdek aynı anda farklı bellek alanlarındaki nesneleri gezer.
  - Bu süreçte CPU ile bellek arasındaki veri yolu yeterince geniş değilse, bellek bant genişliği darboğaza dönüşebilir.
  - Ayrıca fiziksel olarak mesafe olduğundan, her bir gezinme adımı nispeten büyük bir gecikme yaratır.
- Küçük nesnelerin çok olduğu durumlar
  - Derinliği fazla olan veya çok sayıda alt düğümü bulunan ağaç ya da graf yapılarını Go ile işletiyorsanız, GC bu nesnelerin tümünü gezmek zorundadır.
  - Bu süreçte nesneler farklı bellek bölgelerine dağılmışsa, ilk nedenden dolayı gecikme oluşur.
  - Ayrıca küçük nesneler çoksa GC bunların hepsini gezmek zorunda olduğundan, GC çalışırken CPU çekirdekleri önemli bir kapasiteyi GC'ye ayırarak iş yapmak zorunda kalır.

Golang ekibi bu sorunları çözmek amacıyla GreenTea GC'yi duyurmuştur.

## Artık Yeşil Çaya Vakit Yok

### Yeşil Çayı Elinden Alan Şey Nedir

Mevcut GC için en hızlı çözümün uygulanabileceği alan, bellek yerelliği (memory locality) olarak görülmektedir. Yani nesnelerin birbirine yakın konumlandırılarak bellek atlamalarının en aza indirilmesidir. Ancak kod yazan programcıların kalıplarını zorlamak mümkün değildir ve iş akışına bağlı olarak nesne tahsisleri öngörülemez.

Bu nedenle Golang ekibinin seçtiği yöntem **bellek span'i (Memory Span)** olmuştur.

### Bellek Span'i Nedir?

Bellek span'i, nispeten büyük bir bellek bölgesinin tahsis edilip içine küçük nesnelerin yerleştirildiği alandır. GreenTea GC adı verilen yeni GC ise bu bellek span'leri üzerinde çöp toplama işlemini gerçekleştirir. Ayrıntılı davranışı mevcut Tri-Color Mark and Sweep ile hemen hemen aynıdır.

### GreenTea GC'nin Çalışması

Öncelikle GreenTea GC bir bellek span'i tahsis eder. Boyutu daha önce belirtildiği gibi, makul bir büyüklük olan 8KiB'dir. Bu alanın içine en fazla 512 bytes boyutunda nesneler tahsis edilebilir. Örnek verilen ağaç veya graf düğümlerinin boyutu ya da genel olarak heap'e kaçan yapıların boyutu bunun üzerine çıkması zor bir seviyededir. 512 bytes ve altındaki nesneler heap'e kaçtıkça bu bellek span'inde birikir ve span dolduğunda yeni bir bellek span'i tahsis edilir.

GC gerçekleştiğinde GreenTea GC bu bellek span'lerini bir kuyruğa koyar ve sırayla inceler. Bu süreçte GreenTea GC, mevcut GMP modeline oldukça benzer bir zamanlama (scheduling) kullanır. İş çalma (work stealing) gibi alanlar da uygulanmıştır. Her neyse, kuyruktan bir bellek span'i çeken worker, kendisine atanmış bellek span'inin içindeki nesneleri inceler. Bu süreçte Tri-Color Mark and Sweep aynı şekilde kullanılır.

### Bunun Faydası Nedir?

Bu süreçte mevcut GC ile farkı kabaca bakıldığında yalnızca bir noktadır. Tek seferde GC'nin gerçekleştirildiği birim **nesne**den **bellek span'i**ne dönüşmüştür. Bu sayede GC şu avantajlara sahip olur:

- Bellek yerelliği: Nesneler bellek span'inde bir araya toplandığı için nesneleri gezerken bellek atlamaları en aza iner. Yani CPU önbelleğinden (cache) en üst düzeyde yararlanılabilir.
- GC performans artışı: GC'nin bellek span'i birimiyle çalıştırılması sayesinde, GC çok çekirdekli ortamda daha verimli çalışır.
- Bellek tahsisi optimizasyonu: Bellek span'leri sabit boyutta tahsis edildiğinden, küçük nesneler tahsis edilirken bellek tahsis ek yükü azalır ve parçalanma olasılığı düşer. Bu da bellek serbest bırakma verimliliğini artırır.

Kısaca söylemek gerekirse, artık daha sık ve daha rahat bir zihinle 512 bytes ve altındaki nesneleri tahsis edebiliriz.

Ancak burada da belirli ölçüde avantajlı durumlar bulunmaktadır.

- Ağaç/graf yapıları: Dallanma faktörünün (fan-out) yüksek olduğu ve değişikliklerin pek sık yaşanmadığı durumlar
  - B+ ağaçları, Trie, AST (Abstract Syntax Tree)
  - Önbellek dostu veri yapıları
- Toplu işleme: Küçük verilerin büyük miktarda tahsis edildiği iş akışları
  - JSON ayrıştırma ile oluşturulan çok sayıda küçük nesne
  - Veritabanı sonuç kümesinden elde edilen DAO nesneleri

Bu durumlarda GreenTea GC, mevcut GC'ye göre daha iyi performans gösterebilir. Ancak her durumda uygulanabilir değildir; özellikle nesneler farklı bellek bölgelerine dağılmışsa, hâlâ çarpıcı bir performans artışı beklemek zordur.

## Sonuç Olarak

Golang ekibinin uzun vadede GC'yi geliştirmeye devam etme niyeti olduğu anlaşılmaktadır. Bu GreenTea GC küçük ölçekli bir değişiklik olarak değerlendirilebilir ve mevcut GC'nin yerini almamaktadır. Ancak GreenTea GC, Golang ekibinin karşılaştığı veya öngördüğü sorunlara dair ilginç bir örnek olarak görünmektedir. Oldukça karmaşık bir problem olmasına rağmen, nispeten basit bir kavramın eklenmesiyle çözülmeye çalışılması etkileyici bulunmuştur. Kişisel olarak ilginç bir örnek olduğunu düşünüyorum.

GreenTea GC, Go 1.25 ile birlikte sunulan deneysel bir özelliktir. `GOEXPERIMENT=greenteagc` ortam değişkeni kullanılarak etkinleştirilebilir. Bu özellik henüz deneysel olduğundan, üretim ortamında kullanılmadan önce yeterli testlerin yapılması gerekmektedir.

## Referanslar

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