WebAssembly Garbage Collection (WasmGC) ora abilitata per impostazione predefinita in Chrome

Esistono due tipi di linguaggi di programmazione: garbage-collected di programmazione linguaggi e di programmazione che richiedono la gestione manuale della memoria. Alcuni esempi dei primi sono Kotlin, PHP o Java. Esempi di questi ultimi sono C, C++ o Rust. In generale, i linguaggi di programmazione di livello superiore hanno maggiori probabilità di includere garbage collection come funzionalità standard. In questo post del blog ci concentriamo su questi linguaggi di programmazione garbage- collected e su come possono essere compilati in WebAssembly (Wasm). Ma cos'è la garbage collection (spesso indicata come GC) per iniziare?

Supporto dei browser

  • 119
  • 119
  • 120
  • x

Garbage collection

In termini semplificati, l'idea di garbage collection è il tentativo di recuperare la memoria che è stata allocata dal programma, ma alla quale non viene più fatto riferimento. Questa memoria è chiamata spazzatura. Esistono molte strategie per l'implementazione della garbage collection. Uno di questi è il conteggio dei riferimenti, in cui l'obiettivo è contare il numero di riferimenti agli oggetti in memoria. Quando non esistono più riferimenti a un oggetto, questo può essere contrassegnato come non più utilizzato e quindi pronto per la garbage collection. Il garbage collector di PHP utilizza il conteggio dei riferimenti e la funzione xdebug_debug_zval() dell'estensione Xdebug ti consente di sbirciare da dietro. Prendi in considerazione il seguente programma PHP.

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

Il programma assegna un numero casuale trasmesso a una stringa a una nuova variabile chiamata a. Crea quindi due nuove variabili, b e c, e assegna loro il valore a. In seguito, riassegna b al numero 42 e poi annulla l'impostazione di c. Infine, imposta il valore di a su null. Annotando ogni passaggio del programma con xdebug_debug_zval(), puoi vedere il contatore di riferimento del garbage collector in funzione.

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

L'esempio riportato sopra restituirà i log seguenti, dove puoi vedere come il numero di riferimenti al valore della variabile a diminuisce dopo ogni passaggio, il che ha senso data la sequenza di codice. (ovviamente il tuo numero casuale sarà diverso).

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

Esistono altre sfide relative alla garbage collection, come il rilevamento dei cicli, ma per questo articolo è sufficiente una conoscenza di base del conteggio dei riferimenti.

I linguaggi di programmazione sono implementati in altri linguaggi

Può sembrare un'inizio, ma i linguaggi di programmazione sono implementati in altri linguaggi. Ad esempio, il runtime PHP viene implementato principalmente in C. Puoi controllare il codice sorgente PHP su GitHub. Il codice di garbage collection PHP si trova principalmente nel file zend_gc.c. La maggior parte degli sviluppatori installa PHP tramite il gestore di pacchetti del proprio sistema operativo. Tuttavia, gli sviluppatori possono anche creare PHP dal codice sorgente. Ad esempio, in un ambiente Linux, i passaggi ./buildconf && ./configure && make consentono di creare PHP per il runtime Linux. Ma questo significa anche che il runtime PHP può essere compilato per altri runtime, come Wasm.

Metodi tradizionali di portabilità dei linguaggi nel runtime Wasm

Indipendentemente dalla piattaforma su cui è in esecuzione PHP, gli script PHP vengono compilati nello stesso bytecode ed eseguiti da Zend Engine. Zend Engine è un ambiente di compilazione e runtime per il linguaggio di scripting PHP. È composta dalla macchina virtuale (VM) Zend, composta dal compilatore Zend e dall'esecutore Zend. I linguaggi come PHP implementati in altri linguaggi di alto livello come il C di solito presentano ottimizzazioni che hanno come target architetture specifiche, come Intel o ARM, e richiedono un backend diverso per ogni architettura. In questo contesto, Wasm rappresenta una nuova architettura. Se la VM ha un codice specifico per l'architettura, come la compilazione just-in-time (JIT) o anticipata (AOT), lo sviluppatore implementa anche un backend per JIT/AOT per la nuova architettura. Questo approccio ha molto senso perché spesso la parte principale del codebase può essere ricompilata per ogni nuova architettura.

Dato quanto sia Wasm di basso livello, è naturale provare lo stesso approccio lì: ricompilare il codice della VM principale con il relativo parser, il supporto delle librerie, la garbage collection e l'ottimizzatore per Wasm e implementare un backend JIT o AOT per Wasm, se necessario. Questo è stato possibile fin dall'MVP di Wasm e funziona bene in molti casi. Infatti, il WordPress Playground è basato sul PHP compilato con Wasm. Scopri di più sul progetto nell'articolo Creare esperienze WordPress nel browser con WordPress Playground e WebAssembly.

Tuttavia, PHP Wasm viene eseguito nel browser nel contesto del linguaggio host JavaScript. In Chrome, JavaScript e Wasm vengono eseguiti in V8, il motore JavaScript open source di Google che implementa ECMAScript come specificato in ECMA-262. Inoltre, V8 dispone già di un garbage collector. Ciò significa che gli sviluppatori che utilizzano, ad esempio, PHP compilato con Wasm, finiscono per inviare un'implementazione garbage collector del linguaggio trasferito (PHP) al browser che dispone già di un garbage collector, che è uno spreco come sembra. È qui che entra in gioco WasmGC.

L'altro problema del vecchio approccio di consentire ai moduli Wasm di creare il proprio GC sulla memoria lineare di Wasm è che non c'è quindi alcuna interazione tra il garbage collector di Wasm e il garbage collector integrato del linguaggio compiled-to-Wasm, che tende a causare problemi come perdite di memoria e tentativi di raccolta inefficienti. Consentire ai moduli Wasm di riutilizzare il GC integrato esistente evita questi problemi.

Portare i linguaggi di programmazione a nuovi runtime con WasmGC

WasmGC è una proposta del WebAssembly Community Group. L'attuale implementazione di Wasm MVP è in grado di gestire solo numeri, ovvero numeri interi e fluttuanti, in memoria lineare e, con la proposta relativa ai tipi di riferimento, Wasm può inoltre conservare i riferimenti esterni. WasmGC ora aggiunge tipi di heap struct e array, il che significa che supporta l'allocazione della memoria non lineare. Ogni oggetto WasmGC ha una struttura e un tipo fissi, che consentono alle VM di generare facilmente un codice efficiente per accedere ai propri campi senza il rischio di deottimizzazioni tipiche dei linguaggi dinamici come JavaScript. Questa proposta aggiunge quindi un supporto efficiente per i linguaggi gestiti di alto livello a WebAssembly, tramite tipi di heap struct e array che consentono ai compilatori di linguaggio che hanno come target Wasm di integrarsi con un garbage collector nella VM host. In termini semplificati, questo significa che con WasmGC, la portabilità di un linguaggio di programmazione in Wasm significa che il garbage collector del linguaggio di programmazione non deve più far parte della porta, ma può essere utilizzato il garbage collector esistente.

Per verificare l'impatto reale di questo miglioramento, il team Wasm di Chrome ha compilato le versioni del Benchmark Fannkuch (che assegna le strutture di dati man mano che funzionano) da C, Rust e Java. I file binari C e Rust potrebbero variare da 6.1 K a 9.6 K a seconda dei vari flag del compilatore, mentre la versione Java è molto più piccola (solo 2.3 K). C e Rust non includono un garbage collector, ma raggruppano comunque malloc/free per gestire la memoria e il motivo per cui Java è più piccolo qui perché non ha bisogno di raggruppare alcun codice di gestione della memoria. Questo è solo un esempio specifico, ma mostra che i file binari WasmGC hanno il potenziale di essere molto piccoli, e questo è ancora prima di qualsiasi lavoro significativo sull'ottimizzazione delle dimensioni.

Guardare un linguaggio di programmazione trasferito da WasmGC in azione

Kotlin Wasm

Uno dei primi linguaggi di programmazione a essere portato su Wasm grazie a WasmGC è Kotlin, nella forma di Kotlin/Wasm. La demo, con codice sorgente gentilmente dal team Kotlin, viene mostrata nell'elenco che segue.

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"

Ora potresti chiederti qual è il punto, dal momento che il codice Kotlin riportato sopra è costituito essenzialmente dalle API JavaScript OM convertite in Kotlin. Inizia ad avere più senso in combinazione con Compose Multiplatform, che consente agli sviluppatori di sfruttare l'UI che potrebbero aver già creato per le proprie app Android Kotlin. Dai un'occhiata a un'esplorazione iniziale di questo argomento con la demo del visualizzatore di immagini Kotlin/Wasm ed esplora il relativo codice sorgente, anche per gentile concessione del team di Kotlin.

Dart e Flutter

Anche i team di Dart e Flutter di Google stanno preparando il supporto per WasmGC. Il lavoro di compilazione di Dart-to-Wasm è quasi completo e il team sta lavorando al supporto degli strumenti per fornire applicazioni web Flutter compilate in WebAssembly. Puoi leggere lo stato attuale del lavoro nella documentazione di Flutter. La demo seguente è l'anteprima di Flutter WasmGC.

Scopri di più su WasmGC

Questo post del blog ha appena grattato la superficie e offre principalmente una panoramica generale di WasmGC. Per saperne di più sulla funzionalità, visita questi link:

Ringraziamenti

Immagine hero di Gary Chan su Unsplash. Questo articolo è stato rivisto da Matthias Liedtke, Adam Klein, Joshua Bell, Alon Zakai, Jakob Kummerow, Clemens Backes, Emanuel Ziegler e Rachel Andrew.