WebAssembly Çöp Toplama (WasmGC) artık Chrome'da varsayılan olarak etkin

İki tür programlama dili vardır: çöp toplama özellikli programlama dilleri ve manuel bellek yönetimi gerektiren programlama dilleri. Kotlin, PHP veya Java, bu türden birçok dilin örnekleridir. C, C++ veya Rust, ikinci kategoriye örnek verilebilir. Genel bir kural olarak, daha üst düzey programlama dillerinde çöp toplama işlemi standart bir özellik olarak bulunur. Bu blog yayınında, çöp toplama özellikli programlama dillerine ve bunların WebAssembly'ye (Wasm) nasıl derlenebileceğine odaklanıyoruz. Ancak öncelikle çöp toplama (genellikle GC olarak adlandırılır) nedir?

Browser Support

  • Chrome: 119.
  • Edge: 119.
  • Firefox: 120.
  • Safari: 18.2.

Atık toplama

Basit bir ifadeyle, çöp toplama fikri, program tarafından ayrılan ancak artık referans verilmeyen belleği geri kazanma girişimidir. Bu tür belleklere çöp adı verilir. Çöp toplama işlemini uygulamak için birçok strateji vardır. Bunlardan biri, bellekteki nesnelere yapılan referansların sayısını saymayı amaçlayan referans sayımıdır. Bir nesneye artık referans verilmediğinde, nesne artık kullanılmıyor olarak işaretlenebilir ve böylece çöp toplama işlemine hazır hale gelir. PHP'nin çöp toplayıcısı referans sayımı kullanır ve Xdebug uzantısının xdebug_debug_zval() işlevini kullanarak bu işlevin nasıl çalıştığını görebilirsiniz. Aşağıdaki PHP programını inceleyin.

<?php
  $a= (string) rand();
  $c = $b = $a;
  $b = 42;
  unset($c);
  $a = null;
?>

Program, dizeye dönüştürülmüş rastgele bir sayıyı a adlı yeni bir değişkene atar. Ardından b ve c olmak üzere iki yeni değişken oluşturur ve bunlara a değerini atar. Ardından, b öğesini 42 numarasına yeniden atar ve c öğesini ayarlanmamış hale getirir. Son olarak, a değerini null olarak ayarlar. Programın her adımını xdebug_debug_zval() ile açıklayarak çöp toplayıcının referans sayacının nasıl çalıştığını görebilirsiniz.

<?php
  $a= (string) rand();
  $c = $b = $a;
  xdebug_debug_zval('a');
  $b = 42;
  xdebug_debug_zval('a');
  unset($c);
  xdebug_debug_zval('a');
  $a = null;
  xdebug_debug_zval('a');
?>

Yukarıdaki örnekte, değişkenin a değerine yapılan referans sayısının her adımdan sonra nasıl azaldığını gösteren aşağıdaki günlükler oluşturulur. Bu, kod sırası göz önüne alındığında mantıklıdır. (Rastgele numaranız elbette farklı olacaktır.)

a:
(refcount=3, is_ref=0)string '419796578' (length=9)
a:
(refcount=2, is_ref=0)string '419796578' (length=9)
a:
(refcount=1, is_ref=0)string '419796578' (length=9)
a:
(refcount=0, is_ref=0)null

Çöp toplama ile ilgili döngüleri algılama gibi başka zorluklar da vardır ancak bu makale için referans sayımı hakkında temel düzeyde bilgi sahibi olmak yeterlidir.

Programlama dilleri, diğer programlama dillerinde uygulanır.

Bu durum, Inception filmindeki gibi iç içe geçmiş bir yapıya benzetilebilir ancak programlama dilleri, diğer programlama dillerinde uygulanır. Örneğin, PHP çalışma zamanı öncelikle C dilinde uygulanır. PHP kaynak kodunu GitHub'da inceleyebilirsiniz. PHP'nin atık toplama kodu, temel olarak zend_gc.c dosyasında bulunur. Çoğu geliştirici, PHP'yi işletim sisteminin paket yöneticisi aracılığıyla yükler. Ancak geliştiriciler kaynak kodundan PHP'yi de oluşturabilir. Örneğin, Linux ortamında ./buildconf && ./configure && make adımları, Linux çalışma zamanı için PHP'yi oluşturur. Ancak bu, PHP çalışma zamanının diğer çalışma zamanları için de derlenebileceği anlamına gelir. Örneğin, tahmin ettiğiniz gibi Wasm.

Dilleri Wasm çalışma zamanına taşımanın geleneksel yöntemleri

PHP'nin üzerinde çalıştığı platformdan bağımsız olarak PHP komut dosyaları aynı bayt koduna derlenir ve Zend Engine tarafından çalıştırılır. Zend Engine, PHP komut dosyası dili için bir derleyici ve çalışma zamanı ortamıdır. Zend Compiler ve Zend Executor'dan oluşan Zend Virtual Machine (VM) içerir. C gibi diğer üst düzey dillerde uygulanan PHP gibi diller genellikle Intel veya ARM gibi belirli mimarileri hedefleyen optimizasyonlara sahiptir ve her mimari için farklı bir arka uç gerektirir. Bu bağlamda Wasm, yeni bir mimariyi temsil eder. Sanal makinede, tam zamanında (JIT) veya önceden (AOT) derleme gibi mimariye özgü kod varsa geliştirici, yeni mimari için JIT/AOT'nin arka ucunu da uygular. Bu yaklaşım oldukça mantıklıdır. Çünkü genellikle kod tabanının ana kısmı her yeni mimari için yeniden derlenebilir.

Wasm'ın ne kadar düşük seviyeli olduğu göz önüne alındığında, aynı yaklaşımı burada da denemek doğaldır: Ana VM kodunu ayrıştırıcısı, kitaplık desteği, çöp toplama ve optimize edicisiyle birlikte Wasm'a yeniden derleyin ve gerekirse Wasm için bir JIT veya AOT arka ucu uygulayın. Bu, Wasm MVP'den beri mümkündür ve birçok durumda pratikte iyi çalışır. Hatta Wasm'ye derlenen PHP, WordPress Playground'u desteklemektedir. Proje hakkında daha fazla bilgiyi WordPress Playground ve WebAssembly ile tarayıcı içi WordPress deneyimleri oluşturma başlıklı makalede bulabilirsiniz.

Ancak PHP Wasm, tarayıcıda ana dil JavaScript bağlamında çalışır. Chrome'da JavaScript ve Wasm, V8'de çalıştırılır. V8, ECMA-262'de belirtildiği gibi ECMAScript'i uygulayan Google'ın açık kaynaklı JavaScript motorudur. Ayrıca V8'de zaten bir çöp toplayıcı var. Bu nedenle, örneğin Wasm'ye derlenen PHP'yi kullanan geliştiriciler, taşınan dilin (PHP) çöp toplayıcı uygulamasını, zaten çöp toplayıcısı olan tarayıcıya gönderir. Bu, kulağa geldiği kadar israf edici bir durumdur. WasmGC bu noktada devreye girer.

Wasm modüllerinin Wasm'ın doğrusal belleği üzerinde kendi çöp toplayıcılarını oluşturmasına izin veren eski yaklaşımın bir diğer sorunu, Wasm'ın kendi çöp toplayıcısı ile Wasm'a derlenen dilin üstüne inşa edilmiş çöp toplayıcısı arasında etkileşim olmamasıdır. Bu durum, bellek sızıntıları ve verimsiz toplama girişimleri gibi sorunlara neden olur. Wasm modüllerinin mevcut yerleşik GC'yi yeniden kullanmasına izin vermek bu sorunları önler.

WasmGC ile programlama dillerini yeni çalışma zamanlarına taşıma

WasmGC, WebAssembly Topluluk Grubu'nun bir önerisidir. Mevcut Wasm MVP uygulaması yalnızca doğrusal bellekteki sayılarla (yani tam sayılar ve kayan sayılar) işlem yapabilir. Referans türleri önerisiyle birlikte Wasm, harici referansları da tutabilir. WasmGC artık struct ve array yığın türlerini ekliyor. Bu da doğrusal olmayan bellek ayırma desteği anlamına geliyor. Her WasmGC nesnesinin sabit bir türü ve yapısı vardır. Bu sayede sanal makineler, JavaScript gibi dinamik dillerde görülen optimizasyon kaldırma riski olmadan alanlarına erişmek için verimli kod oluşturabilir. Bu teklif, Wasm'ı hedefleyen dil derleyicilerinin ana makine VM'sindeki bir çöp toplayıcıyla entegre olmasını sağlayan yapı ve dizi yığın türleri aracılığıyla WebAssembly'ye üst düzey yönetilen diller için verimli destek ekler. Basit bir ifadeyle bu, WasmGC ile bir programlama dilini Wasm'ye taşımanın, programlama dilinin çöp toplayıcısının artık taşıma işlemine dahil edilmesi gerekmediği, bunun yerine mevcut çöp toplayıcının kullanılabileceği anlamına gelir.

Bu iyileştirmenin gerçek dünyadaki etkisini doğrulamak için Chrome'un Wasm ekibi, Fannkuch karşılaştırma testinin (çalışırken veri yapıları ayırır) C, Rust ve Java sürümlerini derledi. C ve Rust ikili dosyaları, çeşitli derleyici işaretlerine bağlı olarak 6,1 K ile 9,6 K arasında olabilir. Java sürümü ise yalnızca 2,3 K ile çok daha küçüktür. C ve Rust'ta çöp toplayıcı bulunmaz ancak bellek yönetimi için malloc/free paketlenir. Java'nın daha küçük olmasının nedeni ise bellek yönetimi kodu paketlemesine gerek olmamasıdır. Bu yalnızca belirli bir örnektir ancak WasmGC ikililerinin çok küçük olma potansiyeline sahip olduğunu gösterir. Bu durum, boyut için optimizasyon konusunda önemli bir çalışma yapılmadan önce bile geçerlidir.

WasmGC'ye taşınmış bir programlama dilinin nasıl çalıştığını görme

Kotlin Wasm

WasmGC sayesinde Wasm'ye taşınan ilk programlama dillerinden biri, Kotlin/Wasm biçimindeki Kotlin'dir. Kotlin ekibinin izniyle kaynak kodu içeren demo, aşağıdaki listede gösterilmektedir.

import kotlinx.browser.document
import kotlinx.dom.appendText
import org.w3c.dom.HTMLDivElement

fun main() {
    (document.getElementById("warning") as HTMLDivElement).style.display = "none"
    document.body?.appendText("Hello, ${greet()}!")
}

fun greet() = "world"

Yukarıdaki Kotlin kodu temelde JavaScript OM API'lerinin Kotlin'e dönüştürülmesinden oluştuğu için bu kodun ne işe yaradığını merak ediyor olabilirsiniz. Geliştiricilerin Android Kotlin uygulamaları için oluşturmuş olabilecekleri kullanıcı arayüzünü temel alarak geliştirmeler yapmasına olanak tanıyan Compose Multiplatform ile birlikte kullanıldığında daha anlamlı hale gelir. Kotlin ekibinin katkılarıyla geliştirilen Kotlin/Wasm görüntüleyici ile bu konudaki ilk keşifleri inceleyin.

Kotlin/Wasm görüntüleyici demosu.

Dart ve Flutter

Google'daki Dart ve Flutter ekipleri de WasmGC desteği için hazırlık yapıyor. Dart'tan Wasm'ye derleme çalışması neredeyse tamamlandı. Ekip, WebAssembly'ye derlenen Flutter web uygulamalarını sunmak için araç desteği üzerinde çalışıyor. Çalışmanın mevcut durumu hakkında bilgileri Flutter dokümanlarında bulabilirsiniz. Aşağıdaki demo, Flutter WasmGC Önizlemesi'dir.

WasmGC hakkında daha fazla bilgi

Bu blog yayınında WasmGC ile ilgili yalnızca yüzeysel bilgiler verilmiş ve çoğunlukla üst düzey bir genel bakış sunulmuştur. Bu özellik hakkında daha fazla bilgi edinmek için aşağıdaki bağlantıları inceleyin:

Teşekkür

Bu makale Matthias Liedtke, Adam Klein, Joshua Bell, Alon Zakai, Jakob Kummerow, Clemens Backes, Emanuel Ziegler ve Rachel Andrew tarafından incelenmiştir.