WebAssembly Garbage Collection (WasmGC) ist jetzt in Chrome standardmäßig aktiviert

Es gibt zwei Arten von Programmiersprachen: automatisch bereinigte Programmiersprachen und Programmiersprachen, die eine manuelle Speicherverwaltung erfordern. Beispiele hierfür sind Kotlin, PHP oder Java. Beispiele für letztere sind C, C++ oder Rust. In der Regel ist die automatische Speicherbereinigung in höherwertigen Programmiersprachen als Standardfunktion wahrscheinlich. In diesem Blogpost konzentrieren wir uns auf solche Programmiersprachen und wie sie zu WebAssembly (Wasm) kompiliert werden können. Aber womit beginnt die automatische Speicherbereinigung (oft als automatische Speicherbereinigung bezeichnet)?

Unterstützte Browser

  • 119
  • 119
  • 120
  • x

Automatische Speicherbereinigung

Vereinfacht gesagt ist das Konzept der automatischen Speicherbereinigung der Versuch, Arbeitsspeicher freizugeben, der vom Programm zugewiesen wurde, aber nicht mehr referenziert wird. Ein solcher Speicher wird als Speicherbereinigung bezeichnet. Es gibt viele Strategien für die Implementierung der automatischen Speicherbereinigung. Eine davon ist die Referenzzählung. Hierbei soll die Anzahl der Verweise auf Objekte im Speicher gezählt werden. Wenn es keine Verweise mehr auf ein Objekt gibt, kann es als nicht mehr verwendet und somit für die automatische Speicherbereinigung gekennzeichnet werden. Die automatische Speicherbereinigung von PHP nutzt Referenzzählung und mit der Funktion xdebug_debug_zval() der Xdebug-Erweiterung erhalten Sie einen Einblick in die Details. Betrachten Sie das folgende PHP-Programm.

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

Das Programm weist einer neuen Variablen namens a eine Zufallszahl zu, die in einen String umgewandelt wurde. Anschließend werden die beiden neuen Variablen b und c erstellt und ihnen wird der Wert a zugewiesen. Danach wird b der Nummer 42 neu zugewiesen und c wird aufgehoben. Schließlich wird der Wert von a auf null gesetzt. Wenn Sie jeden Schritt des Programms mit xdebug_debug_zval() annotieren, können Sie sehen, wie der Referenzzähler der automatischen Speicherbereinigung funktioniert.

<?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');
?>

Im obigen Beispiel werden die folgenden Logs ausgegeben, in denen Sie sehen, wie die Anzahl der Verweise auf den Wert der Variablen a nach jedem Schritt abnimmt, was angesichts der Codesequenz sinnvoll ist. Ihre Zufallszahl wird natürlich anders lauten.

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

Es gibt noch andere Herausforderungen bei der automatischen Speicherbereinigung, wie etwa die Erkennung von Zyklen. Für diesen Artikel sind grundlegende Kenntnisse zur Referenzzählung ausreichend.

Programmiersprachen sind in anderen Programmiersprachen implementiert.

Programmiersprachen werden in anderen Programmiersprachen implementiert. Die PHP-Laufzeit ist beispielsweise primär in C implementiert. Sie können sich den PHP-Quellcode auf GitHub ansehen. Der Code für die automatische Speicherbereinigung von PHP befindet sich hauptsächlich in der Datei zend_gc.c. Die meisten Entwickler installieren PHP über den Paketmanager ihres Betriebssystems. Entwickler können PHP auch aus dem Quellcode erstellen. In einer Linux-Umgebung wird beispielsweise mit den Schritten ./buildconf && ./configure && make PHP für die Linux-Laufzeit erstellt. Das bedeutet aber auch, dass die PHP-Laufzeit für andere Laufzeiten kompiliert werden kann, z. B. Wasm.

Traditionelle Methoden zum Portieren von Sprachen in die Wasm-Laufzeit

Unabhängig von der Plattform, auf der PHP ausgeführt wird, werden PHP-Skripts in denselben Bytecode kompiliert und von Zend Engine ausgeführt. Zend Engine ist ein Compiler und eine Laufzeitumgebung für die PHP-Skriptsprache. Es besteht aus der Zend Virtual Machine (VM), die aus dem Zend Compiler und dem Zend Executor besteht. Sprachen wie PHP, die in anderen Programmiersprachen wie C implementiert sind, haben in der Regel Optimierungen, die auf bestimmte Architekturen wie Intel oder ARM abzielen und für jede Architektur ein anderes Back-End benötigen. In diesem Kontext stellt Wasm eine neue Architektur dar. Wenn die VM architekturspezifischen Code wie JIT- oder AOT-Kompilierung (Just-in-Time) oder AOT-Kompilierung hat, implementiert der Entwickler auch ein Back-End für JIT/AOT für die neue Architektur. Dieser Ansatz ist sinnvoll, da der Hauptteil der Codebasis oft einfach für jede neue Architektur neu kompiliert werden kann.

Da es sich um Wasm auf niedriger Ebene handelt, ist es naheliegend, dort den gleichen Ansatz auszuprobieren: Kompilieren Sie den Haupt-VM-Code mit seinem Parser, der Bibliotheksunterstützung, der automatischen Speicherbereinigung und dem Optimierer in Wasm und implementieren Sie bei Bedarf ein JIT- oder AOT-Backend für Wasm. Dies ist seit dem Wasm-MVP möglich und funktioniert in vielen Fällen gut. Tatsächlich basiert WordPress Playground auf PHP kompiliert zu Wasm. Weitere Informationen zu diesem Projekt finden Sie im Artikel Mit WordPress Playground und WebAssembly Browser im Browser erstellen.

PHP Wasm wird im Browser jedoch im Kontext der Hostsprache JavaScript ausgeführt. In Chrome werden JavaScript und Wasm in V8 ausgeführt, der Open-Source-JavaScript-Engine von Google, die ECMAScript wie in ECMA-262 angegeben implementiert. Außerdem hat V8 bereits einen Garbage Collector. Das bedeutet, dass Entwickler, die beispielsweise für Wasm kompiliert wurden, eine automatische Speicherbereinigungsimplementierung der Ported Language (PHP) an den Browser senden, der bereits einen Speicher für die automatische Speicherbereinigung hat, was ebenso verschwenderisch ist, wie es klingt. Hier kommt WasmGC ins Spiel.

Das andere Problem des alten Ansatzes, bei dem Wasm-Module ihre eigene GC auf dem linearen Speicher von Wasm aufbauen können, besteht darin, dass es dann keine Interaktion zwischen dem eigenen Speicher von Wasm und dem integrierten Speicher der kompilierten zu Wasm-Sprache gibt, was häufig zu Problemen wie Speicherlecks und ineffizienten Erfassungsversuchen führt. Wenn Sie Wasm-Module die vorhandene integrierte automatische Speicherbereinigung verwenden lassen, können Sie diese Probleme vermeiden.

Mit WasmGC Programmiersprachen in neue Laufzeiten portieren

WasmGC ist ein Vorschlag der WebAssembly Community Group. Die aktuelle Wasm-MVP-Implementierung kann nur mit Zahlen, d. h. Ganzzahlen und Gleitkommazahlen, im linearen Speicher umgehen. Wenn das Angebot für Referenztypen gerade versendet wird, kann Wasm zusätzlich an externe Referenzen zurückgreifen. WasmGC fügt jetzt Struktur- und Array-Heap-Typen hinzu, wodurch eine nicht lineare Arbeitsspeicherzuweisung unterstützt wird. Jedes WasmGC-Objekt hat einen festen Typ und eine feste Struktur. So können VMs ganz einfach effizienten Code für den Zugriff auf ihre Felder generieren, ohne dass das Risiko von Deoptimierungen bei dynamischen Sprachen wie JavaScript besteht. Dieser Vorschlag verleiht WebAssembly dadurch eine effiziente Unterstützung für verwaltete Sprachen auf hoher Ebene, und zwar durch Struktur- und Array-Heap-Typen, die es Sprachcompilern, die auf Wasm ausgerichtet sind, ermöglichen, eine automatische Speicherbereinigung in die Host-VM einzubinden. Vereinfacht bedeutet dies, dass die Portierung einer Programmiersprache zu Wasm bei WasmGC bedeutet, dass die automatische Speicherbereinigung der Programmiersprache nicht mehr Teil des Ports sein muss, sondern dass stattdessen der vorhandene Garbage Collector verwendet werden kann.

Um die realen Auswirkungen dieser Verbesserung zu überprüfen, hat das Wasm-Team von Chrome Versionen der Fannkuch-Benchmark aus C, Rust und Java kompiliert, die Datenstrukturen während der Funktionsweise zuweist. Die C- und Rust-Binärdateien können abhängig von den verschiedenen Compiler-Flags zwischen 6.1 K und 9.6 K liegen, während die Java-Version mit nur 2.3 K viel kleiner ist. C und Rust enthalten keine automatische Speicherbereinigung, bündeln aber malloc/free zur Verwaltung des Arbeitsspeichers. Java ist hier kleiner, weil es keinen Code zur Speicherverwaltung bündeln muss. Dies ist nur ein konkretes Beispiel, aber es zeigt, dass WasmGC-Binärprogramme das Potenzial haben, sehr klein zu sein, und dies ist sogar noch bevor keine nennenswerte Optimierung der Größe erforderlich ist.

WasmGC-portierte Programmiersprache in Aktion sehen

Kotlin-Wasm

Eine der ersten Programmiersprachen, die dank WasmGC in Wasm portiert wurde, ist Kotlin in Form von Kotlin/Wasm. Die vom Kotlin-Team bereitgestellte Demo mit Quellcode ist in der folgenden Auflistung zu sehen.

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"

Vielleicht fragen Sie sich jetzt, worum es geht. Der obige Kotlin-Code besteht im Wesentlichen aus JavaScript OM APIs, die in Kotlin konvertiert wurden. In Kombination mit Compose Multiplatform ist dies sinnvoller, da Entwickler damit auf der UI aufbauen können, die sie möglicherweise bereits für ihre Android- und Kotlin-Apps erstellt haben. Mit der Demo für Kotlin-/Wasm-Bildanzeigen können Sie sich frühzeitig damit vertraut machen und sich mit dem Quellcode des Kotlin-Teams befassen.

Dart und Flutter

Auch die Dart- und Flutter-Teams bei Google bereiten den Support für WasmGC vor. Die Dart-to-Wasm-Kompilierung ist fast abgeschlossen und das Team arbeitet an der Unterstützung von Tools für die Bereitstellung von Flutter-Webanwendungen, die in WebAssembly kompiliert wurden. Informationen zum aktuellen Stand der Arbeit finden Sie in der Flutter-Dokumentation. Die folgende Demo ist die Flutter WasmGC-Vorschau.

Weitere Informationen zu WasmGC

Dieser Blogbeitrag hat bisher kaum etwas an der Oberfläche gekratzt und bietet vor allem einen allgemeinen Überblick über WasmGC. Weitere Informationen zu dieser Funktion finden Sie unter den folgenden Links:

Danksagungen

Hero-Image von Gary Chan auf Unsplash Dieser Artikel wurde von Matthias Liedtke, Adam Klein, Joshua Bell, Alon Zakai, Jakob Kummerow, Clemens Backes, Emanuel Ziegler und Rachel Andrew bewertet.