1 puan yazan GN⁺ 2025-04-24 | 1 yorum | WhatsApp'ta paylaş
  • Go dili, neredeyse hiç tanımsız davranışa sahip değil ve basit GC (çöp toplayıcı) semantiğine sahip
  • Go'da manuel bellek yönetimi mümkündür ve bu, GC ile iş birliği içinde yapılabilir
  • Arena, aynı yaşam süresine sahip belleği verimli biçimde ayıran bir veri yapısıdır; yazı bunun Go'da nasıl uygulanacağını anlatıyor
  • Mark and Sweep algoritması üzerinden GC'nin belleği nasıl yönettiği açıklanıyor
  • Arena kullanılarak bellek ayırma performansı iyileştirilebilir; bu da çeşitli optimizasyonlarla mümkün olur
  • Write barrier kaldırma, bellek yeniden kullanımı, chunk pooling gibi tekniklerle performans artırılırken GC yükü en aza indirilmeye çalışılıyor
  • Realloc uygulaması, Arena'yı yeniden kullanma ve sıfırlama (Reset) gibi özelliklerle, gerçek büyük ölçekli bellek işlemlerinde güvenli ve hızlı kalıplar sunuluyor

Go'da Arena tabanlı manuel bellek ayırmaya genel bakış

  • Go, net GC davranışı ve neredeyse hiç olmayan Undefined Behavior sayesinde güvenli bir dil
  • unsafe paketi kullanılarak GC'nin iç uygulamasına uygun doğrudan bellek denetimi sağlanabilir
  • Bu yazı, Go'da GC ile iş birliği yapabilen Arena yapısı tabanlı bir bellek ayırıcının nasıl oluşturulacağını anlatıyor

Arena'nın tanımı ve neden gerekli olduğu

  • Arena, aynı yaşam süresine sahip nesneleri verimli biçimde ayırmak için kullanılan bir yapı
  • Genel append yaklaşımı diziyi üstel olarak büyütürken, Arena yeni bloklar ekler ve işaretçi sağlar
  • Standart arayüz şu şekildedir:
    • Alloc(size, align uintptr) unsafe.Pointer

İşaretçiler ve GC'nin çalışma biçimi

  • GC, belleği izleme (mark) ve toplama (sweep) yöntemiyle yönetir
  • Kesin GC için, işaretçi konumu bilgisini veren pointer bits adlı metaveri kullanılır
  • Arena içinde işaretçiler yanlış ele alınırsa, GC işaretçileri izleyemez ve Use-After-Free hatası oluşabilir

Arena tasarımı yöntemi

  • Arena yapısı şu alanlara sahiptir:
    • next, left, cap, chunks
  • Tüm ayırmalar 8 bayt hizalı işlenir ve alan yetmezse nextPow2 ile yeni bir chunk oluşturulur
  • Chunk, []uintptr yerine struct { A [N]uintptr; P *Arena } tipiyle ayrılır; böylece GC, Arena'yı izleyebilir

Arena'da işaretçi güvenliği nasıl sağlanır

  • Yalnızca Arena içinde ayrılmış işaretçiler kullanıldığında, GC tüm Arena'yı canlı tutar
  • İşaretçiler Arena'ya referans verecek şekilde ayarlanarak tüm Arena'nın GC altında yaşamını sürdürmesi garanti edilir
  • Arena'nın ayırma yöntemi şunları yapar:
    • allocChunk() içinde Arena işaretçisini chunk'ın sonuna kaydeder

Performans benchmark sonuçları

  • Varsayılan new ile karşılaştırıldığında, Arena ayırması ortalamada 2 ila 4 katın üzerinde performans artışı gösterir
  • GC yükünün yüksek olduğu durumlarda da Arena yaklaşımı 2 kata kadar daha iyi performans sergiler
  • Write barrier kaldırma ve uintptr kullanımı gibi optimizasyonlar, küçük ayırmalarda %20'ye kadar ek performans sağlar

Chunk yeniden kullanımı ve heap'i devreden çıkarma stratejisi

  • sync.Pool kullanılarak chunk'lar yeniden kullanılabilir
  • runtime.SetFinalizer() ile Arena ortadan kalktığında chunk'lar pool'a geri verilebilir
  • Performans küçük ayırmalarda ciddi biçimde artar, ancak büyük ayırmalarda new'den daha yavaş olabilir

Arena'yı sıfırlama ve yeniden kullanma

  • Reset() metodu ile Arena başlangıç durumuna döndürülebilir
  • Riskli olsa da, belleği yeniden ayırmadan aynı yapı tekrar kullanılabilir
  • Yeniden kullanım sırasında da chunk'lar tekrar kullanılarak performans büyük ölçüde artırılır

Realloc özelliğinin uygulanması

  • Arena içinde realloc işlevi uygulanarak en son ayırma için dinamik genişletme sağlanabilir
  • Bu mümkün değilse yeni bellek ayrılır ve veri kopyalanır

Sonuç ve tam kodun paylaşılması

  • Go'nun GC mekanizması derinlemesine anlaşılıp iç uygulamaya dayanarak Arena tabanlı bir bellek yöneticisi tamamlanıyor
  • Hem güvenlik hem performans sunan bu yapı, doğru kullanıldığında büyük ölçekli veri yapılarının işlenmesinde çok yararlı olabilir
  • Tam uygulama kodu; Arena yapısı ile New, Alloc, Reset, allocChunk, finalize gibi bileşenleri içeriyor

1 yorum

 
GN⁺ 2025-04-24
Hacker News görüşü
  • Bu yazı keyifli bir okuma

    • Bu yazıyı beğendiyseniz veya Go'da bellek tahsisini daha iyi kontrol etmek istiyorsanız, yazdığım pakete göz atmanızı isterim
    • Geri bildirim almak ya da başkalarının kullanması güzel olur
    • Bu paket, runtime'tan ayrı olarak kendi belleğini tahsis ederek GC'yi tamamen atlar
    • Tahsis sırasında pointer türlerine izin vermez, ancak aynı işlevi sunan Reference[T] türüyle bunun yerini doldurur
    • Bellek serbest bırakma işlemi manuel yapılır, bu yüzden garbage collector'a güvenilemez
    • Go'da bu tür özel allocator'lar genelde birlikte oluşturulup yok edilen tahsis gruplarını destekleyen arena'lara yönelir
    • Ancak offheap paketi, büyük ve uzun ömürlü veri yapıları kurarak garbage collection maliyetini sıfıra indirmeyi hedefler
    • Büyük in-memory cache'ler veya veritabanları gibi
  • Yakın zamanda Go'da performans ayarı yaparken, performansı en üst düzeye çıkarmak için çok benzer bir arena tasarımı kullanmak zorunda kaldım

    • unsafe pointer'lar yerine buf ve chunk olarak byte slice'lar kullandım
    • Ama bunu denedim ve daha hızlı değildi, üstelik çok daha karmaşıktı
    • %100 emin olmadan önce tekrar kontrol etmem gerek
  • Birkaç kolay iyileştirme noktası

    • Küçük bir slice ile başlıyor ve bazı payload'lar toplu halde ekleniyorsa, yerleşik append'i çağırmadan önce cap'i daha agresif artıran kendi append'imi yazıyorum
    • unsafe.String, byte slice'tan string'i tahsis yapmadan geçirmek için kullanışlı
    • Uyarıları dikkatle okumak ve ne yaptığını anlamak gerekir
  • Konuyla ilgili değil ama, yandaki minimap hoşuma gitti

    • Uzun teknik yazılarda içerikte gezinirken ya da daha önce okuduğum bir şeye yeniden bakarken kullanışlı
    • Bunu kendi siteme nasıl ekleyebileceğimi merak ediyorum
    • Gerçekten harika
  • Uzun yazıları okumak istemeyenler için özet

    • OP, Go'da unsafe kullanarak allocator işlemlerini hızlandırmak için bir arena allocator kuruyor
    • Özellikle birlikte oluşturulup yok edilen çok sayıda şeyi tahsis ederken faydalı
    • Temel sorun, Go'nun GC'sinin düzgün çalışabilmesi için verinin yerleşimini, özellikle de pointer konumlarını bilmesi gerektiği
    • unsafe.Pointer ile ham byte'lar tahsis edildiğinde, GC arena'nın işaret ettiklerini düzgün göremediği için yanlışlıkla serbest bırakabilir
    • Ancak pointer'lar aynı arena içindeki başka şeyleri gösterdiği sürece çalışmasını sağlamak için, arena'nın bir kısmı hâlâ referanslanıyorsa tüm arena korunuyor
    • (1) sistemden alınan arena'ya ait tüm büyük bellek bloklarını gösteren bir slice (chunk'lar) tutuluyor
    • (2) bu bloklara ek pointer alanları ekleyen yeni bir tür oluşturmak için reflect.StructOf kullanılıyor
    • Böylece GC, chunk'lara olan pointer'ı bulduğunda geri pointer'ı da buluyor, arena'yı canlı olarak işaretliyor ve chunk slice'ını koruyor
    • Ardından çeşitli iç kontrolleri ve write barrier'ları ortadan kaldırmaya yönelik ilginç optimizasyon teknikleri tanıtılıyor
  • İlgili: standart kütüphaneye "memory region" eklenmesi tartışması

    • Önceki arena önerisi
  • İlginç bir konu

    • Go'da off-heap veya arena tarzı allocator'lar geliştirenlerin bellek güvenliğini ve GC etkileşimini genelde nasıl test ettiğini ya da benchmark ettiğini merak ediyorum
  • Go, ekosistemi bozmamayı önceliklendiriyor

    • Bu da Hyrum yasasının runtime'ın belirli gözlemlenebilir davranışlarını koruyacağını varsayabilmeyi sağlıyor
    • Eğer bu iddia doğruysa, Go bir dil olarak evrim açısından çıkmaz sokakta demektir
    • Bu durumda Go'nun ne kadar ilginç olduğundan emin değilim
  • Kısa bir meta not

    • Bu yazı gerçekten çok uzun, bu yüzden arka plan ayrıntılarını okuyacak vaktim yok
    • Örneğin "Mark and Sweep" bölümü dizüstü bilgisayar ekranımda 4 sayfadan fazla yer kaplıyor
    • O bölüm, yazının başlamasından sonra 5 sayfadan fazla ileride başlıyor
    • Bölüm yazımında AI yardımcı olduğu için mi bu kadar kapsamlı hâle geldiğini merak ediyorum
    • İçerik üretmek kolay ama önemli kısımları koruyacak editoryal kararlar alınmamış
    • Ben yalnızca arena allocator kısmını bilmek istiyorum, garbage collection hakkında bir eğitime ihtiyacım yok