WebAssembly Garbage Collection (WasmGC): Soporte Completo en Navegadores en 2026

¿Qué es WebAssembly Garbage Collection (WasmGC)?
WebAssembly (Wasm) fue diseñado originalmente como un objetivo de compilación para lenguajes como C, C++ y Rust — lenguajes que gestionan la memoria de forma manual. Pero, ¿qué sucede con lenguajes que tienen recolección de basura automática, como Java, Kotlin, Dart o Go? Antes de WasmGC, estos lenguajes tenían que incluir su propio recolector de basura completo como parte del binario Wasm compilado, lo que resultaba en archivos enormes, mala integración con las herramientas de desarrollo del navegador y trabajo duplicado que la VM del navegador ya realiza de forma nativa.
La propuesta WasmGC (formalmente parte de Wasm 3.0, estandarizada el 17 de septiembre de 2025) introduce tipos con recolección de basura de primera clase — struct y array — directamente en el sistema de tipos de WebAssembly. En lugar de que los lenguajes con GC compilen su propio asignador de memoria y recolector en memoria lineal, ahora delegan la asignación y recolección de objetos al recolector de basura integrado de la VM del navegador (V8, SpiderMonkey o JavaScriptCore).
Antes de WasmGC: el enfoque de memoria lineal
Antes de WasmGC, compilar un lenguaje con GC a Wasm se veía así:
- El runtime del lenguaje (incluyendo su recolector de basura) se compilaba a Wasm y se enviaba como parte del binario
- Todos los objetos vivían en la memoria lineal de Wasm — un arreglo plano de bytes gestionado manualmente
- El GC embebido tenía que recorrer la memoria lineal para encontrar objetos vivos, sin ayuda de la VM del navegador
- Interactuar con objetos JavaScript requería "código puente" complejo y costoso
- Las DevTools del navegador no podían inspeccionar objetos gestionados por el GC dentro de la memoria lineal
Después de WasmGC: integración nativa con la VM
Con WasmGC, el panorama cambia drásticamente:
- Los lenguajes definen tipos
structyarrayen la sección de tipos del módulo Wasm - La asignación de objetos usa instrucciones
struct.newyarray.new - El GC del navegador rastrea y recolecta estos objetos automáticamente — no se necesita un GC embebido
- Los objetos GC pueden referenciar objetos JavaScript sin fricción y viceversa
- Las DevTools pueden inspeccionar objetos WasmGC de forma nativa
Soporte en navegadores en 2026: cobertura completa
A abril de 2026, WasmGC ha alcanzado el estado Baseline Newly Available (desde el 11 de diciembre de 2024), lo que significa que todos los motores principales de navegadores lo soportan. La cobertura global es de aproximadamente 87.9% de los usuarios según caniuse.com.
| Navegador | Primera versión con WasmGC | Fecha de lanzamiento | Motor |
|---|---|---|---|
| Chrome | 119 | Octubre 2023 | V8 |
| Edge | 119 | Octubre 2023 | V8 (Chromium) |
| Firefox | 120 | Noviembre 2023 | SpiderMonkey |
| Opera | 105 | Finales de 2023 | V8 (Chromium) |
| Safari (macOS e iOS) | 18.2 | Diciembre 2024 | JavaScriptCore |
| Samsung Internet | 25 | 2024 | V8 (Chromium) |
| Opera Mobile | 80 | 2025 | V8 (Chromium) |
Detección de soporte: verificar WasmGC en tiempo de ejecución
Antes de depender de WasmGC, debes verificar que el navegador del usuario lo soporte. El método más confiable es intentar compilar un módulo Wasm mínimo que use tipos GC:
1/**
2 * Detectar soporte de WasmGC intentando compilar un módulo
3 * mínimo que declara un tipo struct GC.
4 *
5 * El binario define:
6 * (module
7 * (type (struct (field i32)))
8 * )
9 */
10async function soportaWasmGC() {
11 try {
12 const bytes = new Uint8Array([
13 0x00, 0x61, 0x73, 0x6d, // magic: \0asm
14 0x01, 0x00, 0x00, 0x00, // version: 1
15 0x01, // ID sección de tipos
16 0x07, // Tamaño de sección: 7 bytes
17 0x01, // 1 tipo
18 0x5f, // constructor tipo struct
19 0x01, // 1 campo
20 0x00, // mutabilidad: inmutable
21 0x7f, // tipo campo: i32
22 ]);
23 await WebAssembly.compile(new WebAssembly.Module(bytes));
24 return true;
25 } catch {
26 return false;
27 }
28}
29
30// Uso
31const tieneGC = await soportaWasmGC();
32if (tieneGC) {
33 console.log('¡WasmGC soportado! Cargando módulo optimizado...');
34 // Cargar módulo compilado con WasmGC
35} else {
36 console.log('WasmGC no soportado. Usando fallback JS o Wasm lineal...');
37 // Cargar alternativa
38}
Lenguajes que se benefician de WasmGC
WasmGC desbloquea la web como un objetivo de primera clase para lenguajes con recolección de basura. Este es el estado actual de cada ecosistema principal:
Kotlin/Wasm — Beta (estable esperado para finales de 2026)
Kotlin/Wasm es posiblemente el objetivo WasmGC más maduro. Graduó de Alpha a Beta en septiembre de 2025, y Compose Multiplatform para Web alcanzó Beta al mismo tiempo. JetBrains ha sido una fuerza impulsora detrás de la adopción de WasmGC.
1// saludo.kt — Ejemplo simple de Kotlin/Wasm
2// Target de compilación: wasmJs (usa WasmGC internamente)
3
4fun saludar(nombre: String): String {
5 val saludo = buildString {
6 append("¡Hola, ")
7 append(nombre)
8 append("! Esto se ejecuta en WasmGC ")
9 append("con recolección de basura nativa del navegador.")
10 }
11 return saludo
12}
13
14// Las data classes se mapean a tipos struct de WasmGC
15data class Usuario(val nombre: String, val puntuacion: Int)
16
17fun procesarUsuarios(usuarios: List<Usuario>): List<Usuario> {
18 // Colecciones, lambdas y data classes funcionan normalmente
19 // Los objetos se asignan como structs WasmGC, no en memoria lineal
20 return usuarios
21 .filter { it.puntuacion > 50 }
22 .sortedByDescending { it.puntuacion }
23}
Para configurar un proyecto Kotlin/Wasm con Gradle:
1// build.gradle.kts
2plugins {
3 kotlin("multiplatform") version "2.1.20"
4}
5
6kotlin {
7 wasmJs {
8 browser {
9 commonWebpackConfig {
10 outputFileName = "app.wasm.js"
11 }
12 }
13 binaries.executable()
14 }
15
16 sourceSets {
17 val wasmJsMain by getting {
18 dependencies {
19 implementation("org.jetbrains.kotlinx:kotlinx-browser:0.3")
20 }
21 }
22 }
23}
24
25// Comando de construcción:
26// ./gradlew wasmJsBrowserProductionWebpack
Dart / Flutter Web — soporte estable de WasmGC
Flutter lanzó soporte estable de WebAssembly en Flutter 3.38 (noviembre 2025), con resultados impresionantes: aproximadamente 40% más rápido en carga inicial y 30% menos uso de memoria comparado con la compilación a JavaScript.
1# Crear un nuevo proyecto Flutter para web con Wasm
2flutter create mi_app_wasm
3cd mi_app_wasm
4
5# Compilar para web usando WebAssembly (WasmGC)
6flutter build web --wasm
7
8# La salida en build/web/ contendrá:
9# main.dart.wasm — Código Dart compilado con WasmGC
10# main.dart.mjs — Bootstrap/código puente JS
11# index.html — Punto de entrada con lógica de fallback
12
13# Para desarrollo con hot reload:
14flutter run -d chrome --wasm
skwasm) tiene problemas de compatibilidad con Firefox y Safari debido a bugs específicos de esos navegadores. Chrome/Chromium es el objetivo más confiable. Flutter automáticamente hace fallback al renderizador CanvasKit (JS) en navegadores no soportados. Sigue el problema de Safari en WebKit Bug 267291.
Java — Backend WebAssembly de GraalVM
Oracle GraalVM para Java 25 introdujo un backend WebAssembly que compila bytecode Java a módulos WasmGC. Este es un logro histórico — Java ahora puede ejecutarse nativamente en navegadores sin applets, plugins ni la incrustación pesada del runtime.
Google ha sido pionero aquí: Google Sheets usa J2Wasm (una herramienta interna) para compilar su motor de cálculo basado en Java a WasmGC, logrando un rendimiento 2x más rápido que la implementación equivalente en JavaScript.
1# Compilar Java a WasmGC usando GraalVM (JDK 25+)
2# Requiere Oracle GraalVM con el componente wasm
3
4# Instalar el componente Wasm
5gu install wasm
6
7# Compilar una aplicación Java a WasmGC
8native-image --target=wasm32-wasi \
9 -o app.wasm \
10 -H:+WasmGC \
11 com.example.Main
12
13# El app.wasm resultante usa tipos struct/array de WasmGC
14# y delega la gestión de memoria al GC del navegador
C# / .NET / Blazor — NO adoptará WasmGC
En una decisión sorprendente pero técnicamente bien fundamentada, Microsoft ha declarado que .NET no adoptará WasmGC v1. Las incompatibilidades fundamentales incluyen:
- WasmGC v1 no puede soportar punteros interiores,
refniSpan<T> - No hay finalización, resurrección, referencias débiles ni handles dependientes
- No hay soporte para GC concurrente
- El código de interoperabilidad C/C++ no puede manipular objetos WasmGC fuera de la memoria lineal
Blazor WebAssembly continúa incluyendo el runtime completo de .NET (con su propio GC) compilado a Wasm con memoria lineal. Microsoft dice que "continuará monitoreando la evolución de la especificación post-v1 de WasmGC."
Go — Sin planes activos
A pesar del interés de la comunidad (94+ votos en el issue #63904 de GitHub), el equipo de Go ha etiquetado el soporte de WasmGC como "Sin planificar". Go actualmente compila a Wasm usando memoria lineal con un GC incluido, resultando en binarios grandes (~10-15MB mínimo). Esta sigue siendo un área de frustración para la comunidad.
Otros lenguajes
| Lenguaje | Estado WasmGC | Notas |
|---|---|---|
| OCaml | Desarrollo activo | Compilador wasocaml dirigido a WasmGC |
| Scheme | Prototipo funcional | Compilador Hoot (Spritely/Guile) |
| Scala | Experimental | Vía puente Scala.js → Wasm o compilación directa |
Beneficios técnicos: ¿por qué importa WasmGC?
1. Binarios dramáticamente más pequeños
Al delegar la recolección de basura al navegador, los módulos WasmGC no necesitan incluir una implementación de GC. La diferencia es notable:
| Benchmark | Binario WasmGC (Java) | Binario memoria lineal (C/Rust) | Reducción |
|---|---|---|---|
| Fannkuch | 2.3 KB | 6.1 – 9.6 KB | ~62-76% |
Para aplicaciones reales, los ahorros son aún más pronunciados porque se elimina no solo el GC sino también el asignador de memoria (implementaciones de malloc/free) y todo el código de contabilidad.
2. Mejor rendimiento
Los objetos WasmGC tienen tipos y estructuras fijos y conocidos en tiempo de compilación. Esto significa que el compilador JIT del navegador puede generar código máquina más eficiente:
- Sin riesgo de desoptimización — a diferencia de los objetos dinámicos de JavaScript, los accesos a campos de struct WasmGC son siempre type-safe
- Sin overhead de shadow stack — las implementaciones de GC en memoria lineal requieren un shadow stack para recorrer la pila de llamadas durante el escaneo de raíces; WasmGC elimina esto por completo
- Inlining especulativo de V8 — entregó aproximadamente un 30% de mejora en la carga de trabajo WasmGC de Google Sheets
- Optimización con Binaryen — aplicar
wasm-opta módulos WasmGC produce un promedio de 1.9x de mejora en velocidad
3. Interoperabilidad perfecta con JavaScript
Los objetos WasmGC viven en el mismo heap que los objetos JavaScript. El GC del navegador puede rastrear referencias entre ellos, eliminando la necesidad de código puente complejo:
1// Interoperabilidad JavaScript con un módulo WasmGC
2const instance = await WebAssembly.instantiateStreaming(
3 fetch('app.wasm'),
4 {
5 imports: {
6 // Las funciones JS pueden recibir referencias WasmGC directamente
7 registrarUsuario(refUsuario) {
8 // La VM maneja la referencia — sin serialización necesaria
9 console.log('Procesando usuario:', refUsuario);
10 }
11 }
12 }
13);
14
15// Las funciones exportadas con WasmGC devuelven referencias GC
16const resultado = instance.exports.crearUsuario('Alicia', 100);
17// 'resultado' es una referencia struct WasmGC — el GC del navegador la rastrea
4. Mejor integración con DevTools
Dado que los objetos WasmGC son ciudadanos de primera clase del GC del navegador, las herramientas de desarrollo pueden:
- Inspeccionar campos y tipos de objetos WasmGC en la pestaña de Memoria
- Rastrear asignaciones y recolecciones del GC
- Perfilar el uso de memoria con precisión
- Detectar fugas de memoria que involucren objetos WasmGC
Impacto real: Flutter Web y Kotlin Multiplatform
Flutter Web con WasmGC
La adopción de WasmGC por parte de Flutter representa uno de los despliegues más grandes de esta tecnología en el mundo real:
- ~40% más rápido en carga inicial comparado con la compilación a JavaScript
- ~30% menos uso de memoria en tiempo de ejecución
- Flutter 3.38 (noviembre 2025) marcó el soporte estable de Wasm
- Flutter 3.35 comenzó a preparar a los desarrolladores para Wasm como el objetivo de compilación predeterminado
1// Flutter Web con WasmGC — ¡sin cambios de código necesarios!
2// El mismo código Dart compila tanto a JS como a WasmGC
3
4import 'package:flutter/material.dart';
5
6void main() {
7 runApp(const MiApp());
8}
9
10class MiApp extends StatelessWidget {
11 const MiApp({super.key});
12
13 @override
14 Widget build(BuildContext context) {
15 return MaterialApp(
16 title: 'Demo Flutter WasmGC',
17 home: Scaffold(
18 appBar: AppBar(title: const Text('¡Ejecutándose en WasmGC!')),
19 body: const Center(
20 child: Text(
21 'Este árbol de widgets es gestionado por el GC del navegador',
22 style: TextStyle(fontSize: 24),
23 ),
24 ),
25 ),
26 );
27 }
28}
Kotlin Multiplatform para Web
Compose Multiplatform para Web (Beta, septiembre 2025) permite a los desarrolladores compartir código UI entre Android, iOS, Desktop y Web — con el objetivo web compilado a WasmGC:
1// Compose Multiplatform — mismo código, múltiples targets incluyendo WasmGC
2@Composable
3fun App() {
4 var contador by remember { mutableStateOf(0) }
5
6 MaterialTheme {
7 Column(
8 modifier = Modifier.fillMaxSize(),
9 horizontalAlignment = Alignment.CenterHorizontally,
10 verticalArrangement = Arrangement.Center
11 ) {
12 Text("Contador: $contador", style = MaterialTheme.typography.headlineMedium)
13 Button(onClick = { contador++ }) {
14 Text("Incrementar")
15 }
16 }
17 }
18}
19
20// Cuando se compila al target wasmJs, toda esta UI
21// se ejecuta como código WasmGC en el navegador
Google Sheets: la prueba a gran escala
Quizás la validación más convincente de WasmGC es la migración de Google del motor de cálculo de Sheets de JavaScript a WasmGC (compilado desde Java vía J2Wasm):
- Resultado inicial: WasmGC sin optimizar era 2x más lento que JavaScript
- Después de optimizaciones de V8 y Binaryen: WasmGC se volvió 2x más rápido que JavaScript
- Eso es una mejora de 4x desde la compilación inicial sin optimizar hasta la versión final optimizada
- Demuestra que WasmGC está listo para producción a escala de Google
WasmGC post-MVP: ¿qué viene después?
WasmGC tal como se incluyó en Wasm 3.0 es el "MVP" (Producto Mínimo Viable). Varias propuestas están en progreso para extender sus capacidades:
| Propuesta | Fase | Qué añade |
|---|---|---|
| JS Promise Integration | Fase 4 (Estandarizar) | async/await transparente entre JS y Wasm — sin wrappers de callbacks |
| Stack Switching | Fase 3 (Implementación) | Habilita corutinas, green threads y async eficiente en Wasm |
| JS String Builtins | Incluido (Wasm 3.0) | Operaciones nativas de strings sin código puente JS — ya disponible |
| Shared-Everything Threads | Fase 1 | Compartir objetos GC entre hilos — crítico para compatibilidad con .NET |
| More Array Constructors | Fase 1 | Formas adicionales de crear y manipular arrays WasmGC |
await directamente de Promises de JavaScript sin el complejo código de trampolín que se requiere actualmente.
Cómo optimizar módulos WasmGC con Binaryen
Binaryen es el kit de herramientas esencial de optimización para WebAssembly. Su herramienta wasm-opt puede mejorar significativamente el rendimiento de los módulos WasmGC:
1# Instalar Binaryen
2npm install -g binaryen
3
4# Optimizar un módulo WasmGC (optimización agresiva)
5wasm-opt -O3 --enable-gc --enable-reference-types \
6 input.wasm -o optimizado.wasm
7
8# Con pases adicionales específicos para WasmGC
9wasm-opt -O3 \
10 --enable-gc \
11 --enable-reference-types \
12 --enable-strings \
13 --type-merging \
14 --type-ssa \
15 --global-refining \
16 --cast-all \
17 --gufa-optimizing \
18 input.wasm -o optimizado.wasm
19
20# Verificar la diferencia de tamaño
21ls -la input.wasm optimizado.wasm
22
23# Esperado: 1.5-2x más pequeño después de la optimización
24# Esperado: 1.9x de mejora promedio en velocidad de ejecución (según benchmarks del equipo de V8)
Limitaciones y consideraciones
A pesar de su potencial transformador, WasmGC tiene limitaciones importantes que debes conocer:
Limitaciones actuales
- Sin punteros interiores: No puedes crear una referencia a un campo dentro de un struct — solo al struct completo. Esta es la razón por la que .NET no puede adoptar WasmGC v1.
- Sin finalización: No hay equivalente al
finalize()de Java o alIDisposablede C# activado por el GC. Los recursos deben gestionarse explícitamente. - Sin referencias débiles en Wasm: Aunque JavaScript tiene
WeakRef, WasmGC v1 no expone capacidades de referencias débiles. - Sin control de GC concurrente: Los módulos Wasm no pueden sugerir ni controlar cuándo se ejecuta el GC — depende completamente de la VM del host.
- Bugs específicos de navegadores: El renderizador Wasm de Flutter tiene problemas en Safari y Firefox a abril de 2026, a pesar de que WasmGC en sí funciona correctamente.
Cuándo NO usar WasmGC
- Código C/C++/Rust: Estos lenguajes gestionan la memoria manualmente y deben seguir usando Wasm con memoria lineal
- .NET/Blazor: Las incompatibilidades fundamentales hacen que WasmGC sea impracticable para el runtime de .NET
- Aplicaciones en tiempo real que requieren control de pausas del GC: No puedes ajustar el GC para cargas de trabajo sensibles a la latencia
Ejemplo completo: aplicación con detección de soporte
Aquí tienes un ejemplo práctico de una página HTML que detecta WasmGC y carga la versión apropiada de la aplicación:
1<!DOCTYPE html>
2<html lang="es">
3<head>
4 <meta charset="UTF-8">
5 <title>Aplicación WasmGC</title>
6</head>
7<body>
8 <div id="root"></div>
9 <script type="module">
10 // Detección de funcionalidad
11 async function soportaWasmGC() {
12 try {
13 const bytes = new Uint8Array([
14 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00,
15 0x01, 0x07, 0x01, 0x5f, 0x01, 0x00, 0x7f,
16 ]);
17 await WebAssembly.compile(new WebAssembly.Module(bytes));
18 return true;
19 } catch {
20 return false;
21 }
22 }
23
24 if (await soportaWasmGC()) {
25 // Cargar aplicación compilada con WasmGC
26 const { default: init } = await import('./app.wasm.js');
27 await init();
28 console.log('Ejecutando con WasmGC - GC nativo del navegador');
29 } else {
30 // Fallback a versión JavaScript
31 const { default: init } = await import('./app.js');
32 await init();
33 console.log('Ejecutando fallback de JavaScript');
34 }
35 </script>
36</body>
37</html>
Referencias y lecturas adicionales
- Can I Use — Tabla de compatibilidad WasmGC
- Chrome Blog — Una nueva forma de llevar lenguajes con GC a WebAssembly eficientemente
- V8 Blog — Guía de portabilidad WasmGC
- WebAssembly.org — Anuncio de Wasm 3.0
- Repositorio de propuestas de WebAssembly
- Documentación de Kotlin/Wasm
- Flutter Web — Compilación WebAssembly
- Binaryen — Optimizador del toolchain WebAssembly
- .NET Runtime — Discusión sobre WasmGC (por qué .NET no lo adoptará)
- Go — Issue de seguimiento de WasmGC
Comments
Sign in to leave a comment
No comments yet. Be the first!
Related Articles
Stay updated
Get notified when I publish new articles. No spam, unsubscribe anytime.