外观
WASM 垃圾回收提案
提案背景与意义
WebAssembly (Wasm) 最初设计为低级的二进制指令格式,主要面向数值计算密集型任务,缺乏对高级语言垃圾回收 (GC) 的原生支持。这意味着 Java、C#、Kotlin、Dart、Scala 或 OCaml 等具有垃圾回收机制的语言在编译到 Wasm 时,必须携带自己的 GC 系统,导致模块体积膨胀和性能开销增加。
WasmGC 提案通过引入原生垃圾回收机制,旨在为这些托管语言提供更自然的编译目标。它使 Wasm 能够更高效地支持高级语言,减少手动内存管理的负担,同时避免通过模拟 GC 带来的性能开销。
核心机制与类型系统
类型系统革新
WebAssembly 3.0 引入了一套全新的垃圾回收类型系统,建立在两种基本关系之上:
- 子类型关系:使用
(sub [final] [type-id] (...))语法定义,类似于面向对象编程中的基类-派生类关系。 - 类型等价关系:处理递归类型定义时的复杂等价性判定。
类型系统示意图:
类型关系
├── 子类型关系 (sub <final> <type-id> ...)
└── 类型等价关系
├── 递归类型块 (rec ...)
├── 内部引用 → (rec.i) 相对引用
└── 外部引用 → 绝对引用结构化数据类型
WasmGC 通过扩展 Wasm 的类型系统和指令集,支持结构体 (struct) 和数组 (array) 等高级数据类型。这使得编译器可以直接定义数据布局,而由 Wasm 引擎负责内存的分配和回收。
结构化数据示例:
wasm
(module
(type $Person (struct
(field $name (ref string))
(field $age i32)
))
(func $createPerson (param $name (ref string)) (param $age i32) (result (ref $Person))
(struct.new $Person
(local.get $name)
(local.get $age)
)
)
(func $getAge (param $person (ref $Person)) (result i32)
(struct.get $Person $age (local.get $person))
)
)代码来源:
递归类型与等价性处理
递归类型块 (rec ...) 是类型系统的重要特性。在类型检查过程中:
- 内部引用会被替换为
(rec.i)形式的相对引用。 - 外部引用则保持为绝对引用。
- 类型等价性的判定规则要求:两个类型在各自递归块中的相对引用相同,且所在递归块相等时,它们才等价。
垃圾回收工作原理
内存管理模型
WasmGC 引入了自动内存管理机制,通过垃圾回收算法自动回收无用内存。与传统的线性内存模型不同,GC 内存由 Wasm 运行时自动管理,无需开发者手动分配和释放。
内存划分示意图:
WasmGC 内存空间
├── 栈内存 (存储局部变量和函数调用上下文)
└── 堆内存 (动态分配)
├── 存活对象 (被根对象或其它对象引用)
└── 垃圾对象 (无法被访问,等待回收)标记-清除算法
WasmGC 采用标记-清除算法进行垃圾回收。该过程分为两个阶段:
- 标记阶段:遍历所有从根对象 (如全局变量、当前函数调用栈中的局部变量等) 出发可达的对象,并标记它们为存活。
- 清除阶段:回收所有未被标记的对象占用的内存,并将其返回给空闲内存池。
对象回收示意图:
标记前: [对象A]→[对象B]→[对象C]→[对象D] (根引用A和C)
标记后: [对象A*]→[对象B*] [对象C*]→[对象D] (*表示存活)
清除后: [对象A]→[对象B] [对象C] (D被回收)类型化引用与安全调用
作为 GC 的基础,Wasm 的类型系统得到了显著增强。类型化引用可以精确描述其所指向的堆值的结构,从而避免了运行时的安全检查。通过新的 call_ref 指令,可以实现完全类型安全且无开销的间接函数调用。
性能优化策略
静态类型优势
WasmGC 的设计注重性能,通过静态类型信息在编译时已知对象布局,避免运行时类型查询,从而减少 GC 开销。
规范化技术
为了提高性能,WebAssembly 实现通常采用“规范化”技术:
- 将所有内部引用替换为
(rec.i)形式。 - 将所有外部引用替换为其指向的规范化类型。
- 通过哈希一致化技术优化存储。
- 在规范化后的类型上,等价性检查简化为指针比较。
确定性执行支持
为了满足区块链、可重现系统等场景对确定性执行的需求,Wasm 标准定义了确定性配置文件。它为浮点数运算和松弛向量指令规定了统一的默认行为,确保了在遵循该配置文件的平台之间,Wasm 程序是完全可移植且可复现的。
与宿主环境集成
JavaScript 交互优化
针对 JavaScript 环境,Wasm 3.0 新增了 JS 字符串内建函数。Wasm 模块可以导入一组新的内建函数,用于直接在 Wasm 代码内部操作作为 externref 传入的 JavaScript 字符串,提升了与宿主环境的交互效率。
跨语言内存管理
WasmGC 允许与 JavaScript 的 GC 协作,避免跨语言内存泄漏。通过定义清晰的接口和引用规则,确保 Wasm 模块与宿主环境之间的对象引用得到正确管理。
跨语言引用示意图:
JavaScript 环境
↓ 引用
WasmGC 对象 ←→ 宿主环境 GC
↓ 协作
统一的内存管理工具链与生态支持
编译器工具链进展
WebAssembly 生态系统正在积极适应 GC 提案。Wasm-tools 项目在 1.233.0 版本增强了对组件模型中更多类型的 GC 支持,为变体、选项和结果等高级类型添加了 GC 降低支持。
同时,新的 MLIR-based Wasm 编译器管道解决了现有编译器对高级功能支持不足的问题。通过引入 MLIR Wasm 方言,支持更高效地编译具有高级语言特性的代码。
多语言支持
WasmGC 使多种编程语言能够更有效地编译到 WebAssembly:
- Java/Kotlin:无需携带完整的 JVM 运行时。
- OCaml:利用 WasmGC 的类型系统表达 OCaml 的 ADT。
- Dart:减少生成的 Wasm 模块大小。
- Python:通过 Pyodide 项目在浏览器中高效运行。
应用场景与未来展望
实际应用场景
WasmGC 为多种应用场景带来了改进:
- 影音处理与游戏:通过 GC、例外处理与 SIMD 的改善获得更佳体验。
- 科学计算:处理更大数据集,得益于 64 位地址空间和多内存支持。
- 前端编辑器:更快的启动速度和更小的模块体积。
- 服务器端应用:在非 Web 环境中处理海量数据。
技术展望
随着 WebAssembly GC 在 2022 年 12 月达到 Stage 4 阶段,该技术已趋于成熟并具备了广泛应用的基础。未来,随着更多工具和优化技术的出现,开发者将能够更高效地管理 Wasm 的内存和进行垃圾回收。