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

İki tür programlama dili vardır: çöp olarak toplanan programlama dilleri ve manuel bellek yönetimi gerektiren programlama dilleri. Pek çok başka dilin yanı sıra Kotlin, PHP veya Java da bu programlama türlerine örnek olarak verilebilir. İkincisi örnekler C, C++ veya Rust'tır. Genel kural olarak, üst düzey programlama dillerinin standart özellik olarak çöp toplama özelliğine sahip olma olasılığı daha yüksektir. Bu blog yayınında, çöp gibi toplanan bu tür programlama dillerine ve bunların WebAssembly'de (Wasm) nasıl derlenebileceğine odaklanacağız. Peki, çöp toplama (genellikle GC olarak adlandırılır) nedir?

Tarayıcı Desteği

  • 119
  • 119
  • 120
  • x

Atık toplama

Basitçe açıklamak gerekirse atık toplama fikri, program tarafından tahsis edilen ancak artık referansta bulunulmayan belleği geri kazanma girişimidir. Bu tür hafızaya çöp kutusu denir. Atık toplamayı uygulamaya yönelik 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 nesneye artık referans kalmadığında, nesne "artık kullanılmıyor" ve dolayısıyla çöp toplama işlemi için hazır olarak işaretlenebilir. PHP'nin çöp toplayıcısı referans sayma yöntemini kullanır ve Xdebug uzantısının xdebug_debug_zval() işlevini kullanmak, işlevin ayrıntılarına göz atmanızı sağlar. Aşağıdaki PHP programını düşünün.

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

Program, a adlı yeni bir değişkene bir dizeye rastgele gönderilen sayıyı atar. Ardından, b ve c şeklinde iki yeni değişken oluşturur ve bunlara a değerini atar. Sonrasında, b öğesini 42 numarasına yeniden atar ve ardından c ayarını kaldırır. Son olarak a değerini null olarak ayarlar. Programın her adımına xdebug_debug_zval() ifadesiyle ek açıklama eklediğ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. Burada, a değişkeninin değerine ilişkin referansların her adımdan sonra nasıl azaldığını görürsünüz. Bu durum, kod sırası göz önüne alındığında mantıklıdır. (Rastgele sayınız tabii ki 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 toplamayla ilgili döngüleri tespit etmek gibi başka zorluklar da vardır, ancak bu makale için referans sayımına dair temel düzeyde bilgi sahibi olmak yeterlidir.

Programlama dilleri, diğer programlama dillerinde uygulanır

Bu ilk gösterim gibi dursa da programlama dilleri diğer programlama dillerinde uygulanır. Örneğin, PHP çalışma zamanı öncelikli olarak C'de uygulanır. GitHub'da PHP kaynak koduna göz atabilirsiniz. PHP'nin çöp toplama kodu temel olarak zend_gc.c dosyasında bulunur. Çoğu geliştirici, PHP'yi işletim sistemlerinin paket yöneticisi üzerinden yükler. Ancak geliştiriciler, kaynak kodundan da PHP oluşturabilirler. Örneğin, bir Linux ortamında, ./buildconf && ./configure && make adımları Linux çalışma zamanı için PHP oluşturur. Ancak bu, aynı zamanda PHP çalışma zamanının Wasm gibi başka çalışma zamanları için de derlenebileceği anlamına gelir.

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

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ünden oluşan 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. Bu bağlamda Wasm, yeni bir mimariyi temsil eder. Sanal makinenin tam zamanında (JIT) veya zamanında derleme (AOT) derlemesi gibi mimariye özgü kodları varsa geliştirici, yeni mimaride JIT/AOT için bir arka uç da uygular. Çoğu zaman kod tabanının ana kısmı her yeni mimari için yeniden derlenebileceğinden bu yaklaşım çok mantıklıdır.

Wasm'in ne kadar düşük seviyeli olduğu göz önünde bulundurulduğunda aynı yaklaşımı burada da denemek gayet doğaldır: Ana sanal makine kodunu ayrıştırıcı, kitaplık desteği, atık toplama ve optimize edici ile Wasm için yeniden derleyin ve gerekirse Wasm için bir JIT veya AOT arka ucu uygulayın. Bu, Wasm MVP'den beri mümkün oldu ve birçok durumda pratikte işe yaradı. Hatta WordPress Playground'u, Wasm için derlenen PHP ile güçlendirir. Proje hakkında daha fazla bilgi edinmek için WordPress Playground ve WebAssembly ile tarayıcı içi WordPress deneyimleri oluşturma başlıklı makaleye göz atın.

Ancak, PHP Wasm, tarayıcıda ana makine dili JavaScript'i bağlamında çalışır. Chrome'da, ECMA-262'de belirtildiği gibi ECMAScript'i uygulayan Google açık kaynak JavaScript motoru JavaScript ve Wasm V8'de çalıştırılır. V8'de zaten bir çöp toplayıcı var. Bu da, örneğin Wasm'da derlenen PHP'den yararlanan geliştiricilerin, zaten bir çöp toplayıcıya sahip olan tarayıcıya taşınan dilin (PHP) bir çöp toplayıcı uygulamasını kullanıma sunması anlamına gelir. Bu da görünüşe göre çok israf yaratır. Bu noktada WasmGC devreye girer.

Wasm modüllerinin Wasm'ın doğrusal belleğinin üzerine kendi GC'lerini oluşturmalarına izin veren eski yaklaşımın diğer sorunu, Wasm'ın kendi çöp toplayıcısı ile Wasm'a derlenen dilin yerleşik çöp toplayıcısı arasında herhangi bir etkileşim olmamasıdır. Bu da bellek sızıntıları ve verimsiz toplama denemeleri gibi sorunlara neden olma eğilimindedir. 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 teklifidir. Mevcut Wasm MVP uygulaması, doğrusal bellekte yalnızca sayılarla, yani tam sayılar ve kayan noktaların işlenebilmesini sağlar. Ayrıca Wasm, gönderilen referans türleri teklifiyle birlikte harici referansları da tutabilir. WasmGC artık struct ve dizi yığın türlerini ekliyor. Bu da doğrusal olmayan bellek ayırma desteği anlamına geliyor. Her WasmGC nesnesinin türü ve yapısı sabittir. Böylece sanal makineler, JavaScript gibi dinamik dillerin optimizasyonu riski olmadan alanlarına erişmek için verimli kodlar oluşturabilir. Böylece bu teklif, Wasm'ı hedefleyen dil derleyicilerin ana makine sanal makinesindeki bir çöp toplayıcıyla entegre olmasını sağlayan struct ve dizi yığın türleriyle WebAssembly'ye üst düzey yönetilen diller için etkili destek sağlar. Daha basit bir şekilde anlatmak gerekirse bu, WasmGC ile bir programlama dilini Wasm'a taşımak, programlama dilinin çöp toplayıcısının artık bağlantı noktasının parçası olmasına gerek olmadığı, bunun yerine mevcut çöp toplayıcının kullanılabildiği anlamına gelir.

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ırmasının (çalıştığı sırada veri yapılarını ayıran) sürümlerini derlemiştir. C ve Rust ikili programları, çeşitli derleyici işaretlerine bağlı olarak 6.1 K ile 9.6 K arasında değişebilir. Java sürümü ise yalnızca 2.3 K ile çok daha küçüktür! C ve Rust bir çöp toplayıcı içermez ancak belleği yönetmek için yine de malloc/free paketinde bulunur ve burada Java'nın daha küçük olmasının nedeni, herhangi bir bellek yönetim kodunu paketlemesi gerekmemesidir. Bu, yalnızca spesifik bir örnek olmakla birlikte, WasmGC ikili programlarının çok küçük olma potansiyeline sahip olduğunu ve bu, boyut için optimize etmeyle ilgili önemli çalışmaların bile öncesinde olduğunu göstermektedir.

WasmGC'nin desteklediği bir programlama dilini iş başında görme

Kotlin Wasm'ı

WasmGC sayesinde Wasm'a taşınan ilk programlama dillerinden biri Kotlin/Wasm biçimindeki Kotlin'dir. Kotlin ekibinin izniyle 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ülen JavaScript OM API'lerinden oluştuğu için şimdi bunun ne olduğunu merak ediyor olabilirsiniz. Bu yaklaşım, geliştiricilerin Android Kotlin uygulamaları için zaten oluşturdukları kullanıcı arayüzünü temel almasını sağlayan Compose Multiplatform ile birlikte daha da anlamlı hale geliyor. Kotlin/Wasm resim görüntüleyici demosu ile ilk zamanlarda bu konuyu keşfe çıkın ve Kotlin ekibinin izniyle birlikte kodun kaynak kodunu keşfedin.

Dart ve Flutter

Google'daki Dart ve Flutter ekipleri de WasmGC için destek hazırlıyor. Dart-to-Wasm derleme çalışması neredeyse tamamlandı ve ekip, WebAssembly'de derlenen Flutter web uygulamalarını sunmaya yönelik araçlar üzerinde çalışıyor. Flutter dokümanlarında çalışmanın mevcut durumu hakkında bilgi edinebilirsiniz. Aşağıdaki demo, Flutter WasmGC Önizlemesi'dir.

WasmGC hakkında daha fazla bilgi

Bu blog yayını, henüz yolun başında değil ve WasmGC'ye genel olarak üst düzey bir genel bakış sunuyor. Bu özellikle ilgili daha fazla bilgi edinmek için şu bağlantıları ziyaret edin:

Teşekkür

Gary Chan tarafından 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 incelendi.