- 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:
- 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
Hacker News görüşü
Bu yazı keyifli bir okuma
Reference[T]türüyle bunun yerini doldururYakı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
Birkaç kolay iyileştirme noktası
unsafe.String, byte slice'tan string'i tahsis yapmadan geçirmek için kullanışlıKonuyla ilgili değil ama, yandaki minimap hoşuma gitti
Uzun yazıları okumak istemeyenler için özet
reflect.StructOfkullanılıyorİlgili: standart kütüphaneye "memory region" eklenmesi tartışması
İlginç bir konu
Go, ekosistemi bozmamayı önceliklendiriyor
Kısa bir meta not