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

İki tür programlama dili vardır: atık toplanan programlama dilleri ve manuel bellek yönetimi gerektiren programlama dilleri. Bunların yanı sıra Kotlin, PHP veya Java da buna örnek gösterilebilir. İkinci özelliklere örnek olarak C, C++ veya Rust verilebilir. Genel bir kural olarak, üst düzey programlama dillerinin standart bir özellik olarak çöp toplamaya sahip olma olasılığı daha yüksektir. Bu blog yayınında, atık olarak toplanan bu tür programlama dillerine ve bunların WebAssembly'de (Wasm) nasıl derlenebileceği ele alındı. Peki, ilk başta atık toplama (genellikle GC olarak adlandırılır) nedir?

Tarayıcı Desteği

  • Chrome: 119..
  • Kenar: 119..
  • Firefox: 120..
  • Safari: desteklenmez..

Atık toplama

Basitleştirilmiş ifadelerle atık toplama fikri, program tarafından ayrılan ancak artık referans verilmeyen belleği geri alma girişimidir. Böyle bir belleğe çöp denir. Atık toplamayı uygulamak için birçok strateji vardır. Bunlardan biri, hedefin bellekteki nesnelere yapılan referansların sayısını saymak olduğu referans sayımıdır. Bir nesne için başka referans kalmadığında, nesne artık kullanılmıyor ve atık toplama için hazır olarak işaretlenebilir. PHP'nin çöp toplayıcısı referans sayımını kullanır ve Xdebug uzantısının xdebug_debug_zval() işlevini kullanarak arka planımıza göz atabilirsiniz. Aşağıdaki PHP programını düşünün.

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

Program, bir dizeye yayınlanan rastgele bir sayıyı a adlı yeni bir değişkene atar. Daha sonra, b ve c adlı iki yeni değişken oluşturup bunlara a değerini atar. Bunun ardından b, 42 numarasına yeniden atanır ve c ayarı kaldırılır. Son olarak, a değerini null olarak ayarlar. Programın her adımını xdebug_debug_zval() ile not ettiğinizde, çöp toplayıcının referans sayacını iş başında 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 örnek, aşağıdaki günlükleri oluşturur. Bu günlüklerde, a değişkeninin değerine yapılan referansların her adımdan sonra nasıl azaldığını görürsünüz. Bu durum, kod dizisine göre mantıklıdır. (Rastgele sayınız elbette farklıdı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

Atık toplama işleminde döngüleri algılama gibi başka zorluklar da vardır, ancak bu makalede referans sayımını anlamak için temel düzeyde bilgi sahibi olmak yeterlidir.

Programlama dilleri diğer programlama dillerinde uygulanır

Bir başlangıç gibi görünse de programlama dilleri diğer programlama dillerinde uygulanmıştır. Örneğin, PHP çalışma zamanı temel olarak C'de uygulanır. GitHub'da PHP kaynak koduna göz atabilirsiniz. PHP'nin atık toplama kodu çoğunlukla 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 PHP kaynak kodundan da geliştirebilir. Örneğin, bir Linux ortamında ./buildconf && ./configure && make adımlarıyla, Linux çalışma zamanı için PHP oluşturulur. Ancak bu aynı zamanda, PHP çalışma zamanının, tahmin ettiğiniz Wasm gibi diğer çalışma zamanları için derlenebileceği anlamına gelir.

Dilleri Wasm çalışma zamanına taşımak için geleneksel yöntemler

PHP komut dosyaları, PHP'nin çalıştığı platformdan bağımsız olarak aynı bayt kodunda derlenir ve Zend Engine tarafından çalıştırılır. Zend Engine, PHP kodlama dili için bir derleyici ve çalışma zamanı ortamıdır. Zend Derleyici ve Zend Yürütücüsü, Zend Sanal Makinesi'nden (VM) oluşur. 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. Wasm bu bağlamda yeni bir mimariyi temsil ediyor. Sanal makinede "tam zamanında" (JIT) veya önceden (AOT) derleme gibi mimariye özgü bir kod varsa geliştirici, yeni mimari için bir JIT/AOT arka ucu da uygular. Bu yaklaşım çok mantıklıdır çünkü kod tabanının ana kısmı genellikle her yeni mimari için yeniden derlenebilir.

Wasm'in düşük seviyeli olduğunu göz önünde bulundurarak, aynı yaklaşımı burada da denemek doğaldır: Ana sanal makine kodunu ayrıştırıcı, kitaplık desteği, atık toplama ve Wasm için optimize ediciyle yeniden derleyin ve gerekirse Wasm için bir JIT veya AOT arka ucu uygulayın. Bu, Wasm MVP'sinden beri mümkündü ve pratikte birçok senaryoda işe yarıyor. Hatta WordPress Playground'u destekleyen, Wasm'a derlenen PHP'dir. 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 makine dilindeki JavaScript bağlamında çalışır. Chrome'da, ECMA-262'de belirtildiği gibi ECMAScript'i uygulayan Google'ın açık kaynak JavaScript motoru olan JavaScript ve Wasm V8'de çalıştırılır. V8'in zaten bir çöp toplayıcısı vardır. Bu, örneğin Wasm'a derlenen PHP'yi kullanan geliştiricilerin, taşınan dilin (PHP) bir çöp toplayıcı uygulamasını, zaten bir çöp toplayıcısı olan tarayıcıya göndermesi anlamına gelir. Bu da göründüğü kadar israfa yol açar. WasmGC burada devreye giriyor.

Eski yaklaşımın, Wasm modüllerinin Wasm'ın doğrusal belleğinin üzerinde kendi GC'sini oluşturmasına izin veren diğer bir sorun, Wasm'ın kendi çöp toplayıcısı ile derlenen Wasm dilinin yerleşik çöp toplayıcısı arasında etkileşim olmamasıdır. Bu da bellek sızıntıları ve verimsiz toplama denemeleri gibi sorunlara yol açabilir. 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 teklifidir. Mevcut Wasm MVP uygulaması, yalnızca doğrusal bellekteki tam sayılar ve kayan sayılarla işlem yapabiliyor. Referans türleri teklifi gönderilmiş olduğundan Wasm ayrıca harici referansları da saklayabilir. WasmGC artık doğrusal olmayan bellek ayırma desteği anlamına gelen struct ve dizi yığın türlerini ekliyor. Her WasmGC nesnesi sabit bir türe ve yapıya sahiptir. Bu, JavaScript gibi dinamik dillerin optimizasyonunu kaldırma riski olmadan sanal makinelerin, alanlarına erişmek için verimli kod oluşturmasını kolaylaştırır. Böylece bu teklif, Wasm'i hedefleyen dil derleyicilerin ana makine sanal makinesindeki bir çöp toplayıcı ile entegre olmasını sağlayan struct ve dizi yığın türleri aracılığıyla WebAssembly'ye üst düzey yönetilen diller için etkili destek sağlar. Basit bir şekilde ifade etmek gerekirse bu, WasmGC ile bir programlama dilinin Wasm'a taşınması, artık programlama dilinin çöp toplayıcısının artık bağlantı noktasının parçası olması gerekmediği anlamına gelir. Bunun yerine mevcut çöp toplayıcı kullanılabilir.

Bu iyileştirmenin gerçek dünyadaki etkisini doğrulamak için Chrome'un Wasm ekibi C, Rust ve Java'dan Fannkuch karşılaştırma (çalışırken veri yapılarını ayırır) sürümlerini derledi. C ve Rust ikili programları, çeşitli derleyici işaretlerine bağlı olarak 6.1 K ile 9,6 K arasında olabilirken Java sürümü sadece 2.3 K ile çok daha küçüktür! C ve Rust'ta çöp toplayıcı yoktur, ancak belleği yönetmek için malloc/free paket halinde bulunurlar. Java'nın burada daha küçük olmasının nedeni, herhangi bir bellek yönetimi kodu paketlemesine gerek olmamasıdır. Bu, tek bir spesifik örnek olsa da WasmGC ikili programlarının çok küçük olma potansiyeline sahip olduğunu gösteriyor. Hatta boyut optimizasyonuyla ilgili önemli bir çalışmadan önce bile bu durum söz konusu.

WasmGC tarafından desteklenen bir programlama dilini iş başında görme

Kotlin Wasm

WasmGC sayesinde Wasm'a getirilen ilk programlama dillerinden biri, Kotlin/Wasm biçimindeki Kotlin'dir. Kotlin ekibi tarafından sağlanan kaynak kodu içeren demo aşağıdaki girişte 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 temel olarak Kotlin'e dönüştürülmüş JavaScript OM API'lerinden oluştuğu için burada ne anlama geldiğini merak ediyor olabilirsiniz. Geliştiricilerin Android Kotlin uygulamaları için önceden oluşturmuş olabilecekleri kullanıcı arayüzünü geliştirmelerine olanak tanıyan Compose Multiplatform ile birlikte kullanıldığında daha anlamlı bir hale geliyor. Kotlin/Wasm resim görüntüleyici demosuyla bu konuyu erkenden keşfedin ve Kotlin ekibinin yardımıyla incelemenin kaynak kodunu inceleyin.

Dart ve Flutter

Google'ın Dart ve Flutter ekipleri de WasmGC için destek hazırlıyor. Dart-to-Wasm derleme çalışması neredeyse tamamlandı. Ekip, WebAssembly'de derlenen Flutter web uygulamalarını yayınlamak için araç desteği üzerinde çalışıyor. Çalışmanın mevcut durumu hakkında bilgi edinmek için Flutter dokümanlarına bakabilirsiniz. Aşağıdaki demo Flutter WasmGC Preview'dur.

WasmGC hakkında daha fazla bilgi

Bu blog yayını henüz yüzeye henüz çıkmamış ve WasmGC hakkında çoğunlukla üst düzey bir genel bakışa sahipti. Özellik hakkında daha fazla bilgi edinmek için şu bağlantılara göz atın:

Teşekkür

Gary Chan'in Unsplash'teki hero resim. Bu makale Matthias Liedtke, Adam Klein, Joshua Bell, Alon Zakai, Jakob Kummerow, Clemens Backes, Emanuel Ziegler ve Rachel Andrew tarafından incelenmiştir.