- Ghostty terminal emülatöründe, uzun süre çalıştığında onlarca GB belleği tüketen ciddi bir sızıntı sorunu tespit edildi
- Sorunun nedeni, PageList yapısının standart dışı bellek sayfalarını yeniden kullanma mantığında
munmap çağrılmaması nedeniyle serbest bırakılmayan belleğin birikmesiydi
- Claude Code CLI sık sık çoklu kod noktası grafikleri ürettiği için, standart dışı sayfa kullanım sıklığı arttı ve sızıntı büyük ölçekte görünür hale geldi
- Düzeltme, standart dışı sayfaların yeniden kullanılmaması ve hemen serbest bırakılması yönünde yapıldı; ayrıca macOS'un VM etiketleme özelliği sızıntının izlenmesi ve doğrulanmasında kullanıldı
- Bu düzeltme, Ghostty'nin en büyük sızıntı sorununun çözümü olarak değerlendiriliyor ve gelecek sürümde (1.3) yer alması planlanıyor
Ghostty'nin bellek sızıntısına genel bakış
- Bazı kullanıcılar, Ghostty'nin uzun süre çalıştıktan sonra 37 GB'tan fazla bellek kullandığını bildirdi
- Sızıntı en az 1.0 sürümünden beri mevcuttu ve son dönemde bazı CLI uygulamaları belirli koşulları sağlayarak sorunu görünür kıldı
- Düzeltme zaten GitHub'a birleştirildi ve nightly derlemeler ile 1.3 kararlı sürümüne dahil edilecek
PageList yapısı ve bellek yönetimi
- Ghostty, terminal içeriğini saklamak için PageList adlı çift bağlı liste yapısını kullanıyor
- Her sayfa; karakterler, stiller, köprüler gibi verileri içeriyor
- Sayfalar
mmap ile ayrılıyor ve standart boyutlu sayfa havuzu (pool) üzerinden yeniden kullanılıyor
- Standart boyutun altındaki sayfalar havuza geri dönüyor
- Standart dışı boyuttaki sayfalar ise doğrudan
munmap ile serbest bırakılmalı
- Yapının kendisi normal olsa da, optimizasyon mantığındaki bir hata sızıntıya yol açtı
Scrollback optimizasyonu ve hatanın nedeni
- Ghostty,
scrollback-limit aşıldığında en eski sayfayı yeniden kullanan bir optimizasyon yapıyor
- Yeni sayfa ayırmak yerine yalnızca işaretçileri ayarlayarak performansı artırıyor
- Sorun, bu süreçte standart dışı sayfanın yalnızca meta verisinin standart boyuta çevrilmesi, gerçek belleğin ise olduğu gibi bırakılmasıydı
- Daha sonra serbest bırakılırken standart sayfa sanıldığı için
munmap çağrılmıyordu
- Bunun sonucunda standart dışı sayfalar serbest bırakılmadan birikiyor ve uzun süreli çalışmada büyük çaplı bellek sızıntısı oluşuyordu
Claude Code ile sızıntının büyük ölçekte görünür olması
- Claude Code CLI, çoklu kod noktası grafikleri sık ürettiği için standart dışı sayfa kullanım sıklığını artırdı
- Ayrıca scrollback çıktısı da fazla olduğundan sızıntı hızla birikti
- Ghostty'nin tasarımında standart dışı sayfaların nadir olması bekleniyordu; ancak Claude Code'un özellikleri nedeniyle sızıntı büyük miktarda yeniden üretilebildi
- Geliştirici, bu hatanın Claude Code'dan değil, Ghostty'nin iç mantığındaki bir kusurdan kaynaklandığını özellikle belirtti
Düzeltmenin içeriği
VM etiketleriyle sızıntıyı izleme
- macOS'un Mach çekirdeği VM etiketleme özelliği kullanılarak PageList bellek ayırmalarına belirli etiketler verildi
- Böylece hata ayıklama sırasında Ghostty'nin bellek bölgeleri net biçimde ayırt edilebildi
- Bu da sızıntının nedenini izleme ve düzeltmeyi doğrulama konusunda büyük fayda sağladı
- Bu özellik sayesinde PageList ile ilgili belleğin serbest bırakılıp bırakılmadığı görsel olarak doğrulanabildi
Ghostty'nin bellek sızıntısını önleme sistemi
- Ghostty, sızıntıları tespit etmek ve önlemek için çeşitli yöntemler kullanıyor
- Hata ayıklama derlemeleri ve birim testlerinde Zig'in sızıntı tespit eden allocator'ı kullanılıyor
- CI ortamında tüm testler valgrind ile çalıştırılıyor
- macOS Instruments ile Swift kodundaki sızıntılar denetleniyor
- GTK ile ilgili PR'ler Valgrind GUI testleri ile doğrulanıyor
- Bu sızıntı yalnızca belirli koşullarda ortaya çıktığı için mevcut testlerle yeniden üretilememişti
- Geriye dönük hataları önlemek için yeni bir test senaryosu eklendi
Sonuç
- Bu olay, Ghostty'de şimdiye kadar görülen en büyük bellek sızıntısı vakası olarak doğrulandı
- Düzeltmeden sonra da kullanıcı raporları ve yeniden üretim testleriyle izleme sürdürülecek
- Topluluğun sağladığı teşhis verileri ve yeniden üretim örnekleri sorunun çözümünde kritik rol oynadı
- Yeniden üretilebilen bir ortam oluşturmanın, bellek sızıntılarını çözmenin anahtarı olduğu vurgulandı
1 yorum
Hacker News yorumları
Gerçekten sevindirici bir haber. Sorunu çözmeye katkı veren herkesi alkışlıyorum
Geçen hafta zaten bu başlıkta bahsedilmiş bir bug'dı
Claude Code bu bug'ı daha fazla kullanıcıya görünür kılan etken olmuş gibi görünüyor, ama benim gibi Claude Code'u hiç kullanmadığı halde aynı sorunu yaşayanlar da vardı
Bir sayfanın “standart dışı (non-standard)” olarak sınıflandırılma ölçütü sanıldığından daha az siyah-beyaz
Ayrıca
scrollback-limit = 0gibi ayarlar kullananlarda sızıntı daha sık yaşanmış olabilir diye düşünüyorumDüzeltme biçimi, gereksiz yere standart dışı sayfaları silip yeniden oluşturuyor olabilir; zaten standart dışı olan eski sayfalar yeniden kullanılamaz mıydı diye düşünmeden edemiyorum
PageList'in çalışma şekli eskiden beri aynıydı; bug varken de yalnızca kapasite ayarlaması sırasında yanlış boyutu görüyordu
Algılanan performansta bir değişiklik olmayacaktır
Önerdiğin alternatif de değerlendirildi, ama mevcut yaklaşım benchmark verileriyle yeterince destekleniyor
Benim de fikrimi değiştirme payım var, ama bu kez bütün dünya görüşünü değiştirmektense sızıntıyı düzeltmeye odaklandım
Gerçekten de segfault üreten, yeniden üretilebilir bir bug'dı
Son 20 yılda CLI'ı bundan daha taze hissettiren başka bir şey olmadı
Harika bir yazıydı. Ghostty'yi yaptığı için mitchellh'ye teşekkürler
Geçen yıl geçiş yaptım ve bir kez bile pişman olmadım
Yalnız, düzeltmenin birkaç ay sonraki özellik sürümüne girecek olması biraz şaşırtıcı geldi
Bir bugfix sürümünde yer alacağını sanmıştım
Sayfa konusu açılır açılmaz “ha, bellek havuzlama” diye düşündüm, sonra da “muhtemelen ring buffer'dır” dedim; gerçekten de scrollback yeniden kullanımı çıktı
Bug'ın nerede olduğunu da hemen tahmin ettim — sayfa belleğinin düzgün serbest bırakılmadığı kısımdaydı
Bellek hizalama diyagramları da çok iyiydi
Yeni bir şey denediğiniz her seferde sızıntı ihtimalinin doğduğunu tekrar hatırlatıyor
Bu hafta Ghostty'ye geçtim ve terminal UI uygulaması geliştirirken OOM çökmesi yaşadım
Sekme çubuğunda UTF8 ikonları kullanan bir yapıydı ve terminal yeniden boyutlandırılınca anında çöküyordu
Yeniden üretmesi kolay olduğu için bug raporu hazırlıyordum, ama blog yazısında anlatılan sorunla çok benzer görünüyor
Umarım çözülür
@mitchellh'ye sordum — bellek görselleştirmelerini hangi araçla yaptığını ve web sitesinin mobilde de çok iyi çalıştığını görünce stack'in ne olduğunu merak ettim
Görselleştirme kodu tek seferlikti, bu yüzden kalite yerine yalnızca doğruluğunu kontrol ettim
Her blog yazısı için namespace'i ayırıyorum, yeniden kullanmıyorum
Uygulamanın tuhaf şeyler yapmadığını (ör. Bitcoin madenciliği, sır sızdırma vb.) kontrol ediyorum
Asıl amaç bilgiyi aktarmak ve bu tür diyagramlar içeriği çok daha kolay anlaşılır kılıyor
Ghostty geliştirmesini takip etmeyi sürdürüyorum
Bir miktar aşırı mühendislik hissi var ama bu tür bug postmortem'leri, işçiliği seven insanlar için çok değerli materyaller
Rust tabanlı bir terminalde bunun performans kaybı olmadan nasıl ele alınacağını merak ediyorum
Ghostty'yi ya da terminal emülatörlerini pek bilmeyen biri olarak bile rahat anlaşılabilen bir yazıydı
Erişilebilirliği ve dostane anlatımı özellikle etkileyiciydi
Yeniden üretilebilir bug raporlarının önemini bir kez daha hissettirdi
Birinin çıkıp “Rust kullanılsaydı bunlar olmazdı” demesini bekliyorum
Rust, dil düzeyinde ‘bellek sızıntısı güvenliği (leak safety)’ garantisi vermez
Güvenli Rust kodu da bellek sızdırabilir — sadece bu bir güvenlik sorunu değildir
Standart API'de bile Box::leak gibi sızıntıya açıkça izin veren yapılar var
Rust yalnızca istenmeyen sızıntıları yazmayı zorlaştırır, tamamen engellemez