SJ blog
frontend
A

信頼度ランク

S 公式ソース確認済み
A 成功実績多数・失敗例少数
B 賛否両論
C 動作未確認・セキュリティリスク高
Z 個人所感

WebAssembly 3.0 仕様確定——WasmGC・Memory64・例外処理で「4GBの壁」を越え、JavaがブラウザでGCなし動作

2026年4月24日に更新されたWebAssembly 3.0仕様書は、GC統合・64ビットメモリ・例外処理・複数メモリ・末尾呼び出し・128-bit SIMDを標準化。Java/Kotlin/Dart/ScalaがブラウザのGCを直接利用でき、LLM推論や動画編集などのメモリ集約ワークロードが現実的に。

一言結論

WebAssembly 3.0はWasmGCでJava・Kotlin・Dart・ScalaをブラウザのGCに直接接続し、GCランタイムをモジュールに同梱する旧来の方式を廃止。Memory64は4GBの上限を理論上16EBへ拡張し、エッジLLM推論・科学計算・動画編集の現実的ユースケースを開拓した。スレッド(WASI側)とモバイルブラウザのメモリ上限は依然として課題。

背景:Wasm 2.0が抱えていた3つの壁

WebAssemblyは2017年にブラウザ間共通のバイナリ命令セットとしてリリースされて以来、C/C++/Rustのコードをほぼネイティブ速度でブラウザ実行できる技術として普及してきた。しかし実運用では長年3つの制約がボトルネックになっていた。

1. 4GBメモリ上限:Wasm 2.0は32ビットポインタのため最大4GBまでしかアドレスできない。動画のデコードやLLMのKVキャッシュなど、数GBを超えるデータを扱うワークロードは事実上不可能だった。

2. GCの欠如:JavaやKotlinをWasmへコンパイルしようとすると、言語ランタイムのGCをWasmモジュール内に丸ごと同梱する必要があった。これはバイナリサイズの肥大化と初期化時間の増大を招いていた。

3. 統一されていない例外処理:各言語/ツールチェーンが例外をエミュレーションするための独自の迂回策(setjmp/longjmp、テーブルジャンプなど)を持っており、相互運用性もパフォーマンスも劣悪だった。

WebAssembly 3.0 で何が変わったか

2026年4月24日にW3C公式仕様書(webassembly.github.io/spec/core/)が更新され、以下の9機能が標準化された。2025年9月のW3C勧告で正式採択済みであり、主要ブラウザはすでに本番サポートしている。

WasmGC:GCを言語ランタイムではなくエンジンに任せる

WasmGCはstructとarray型の直接ヒープ確保をWasm命令セットに追加する。これによりJavaVMやDart VMはホストJSエンジン(V8・SpiderMonkey・JavaScriptCore)のGCをそのまま使えるようになる。

WasmGC なし(旧方式):
  .wasm ファイル = アプリコード + GC実装 + ランタイム
  バイナリサイズ: ~10MB(Kotlin/JVM の場合)
  初期化: ランタイム全体を起動してから処理開始

WasmGC あり(3.0):
  .wasm ファイル = アプリコード のみ
  バイナリサイズ: ~2MB(同等のKotlin/JVMコード)
  初期化: ブラウザのGCを共有、即座に利用可能

実際に Kotlin/Wasm(WasmGCターゲット)でデータクラスを定義するとこうなる:

// Kotlin側(通常のKotlinコード)
data class Point(val x: Double, val y: Double) {
    fun distanceTo(other: Point): Double =
        Math.sqrt((x - other.x).pow(2) + (y - other.y).pow(2))
}

// コンパイル後のWATイメージ(簡略)
;; (struct.new $Point (f64.const 1.0) (f64.const 2.0))
;; ブラウザのGCがPointインスタンスを管理する

Java・Dart・Scalaも同様の恩恵を受ける。GCの圧迫がなくなるため、ページの初期ロード時のJank(フレームドロップ)が大幅に改善する。

Memory64:4GBの壁を突破

memory64 命令はポインタサイズを64ビットに拡張し、理論上は16EBのアドレス空間を利用できる(ブラウザの実装はセキュリティ上より小さく制限しており、Chromeは16GBが現在の上限)。

// JS側からMemory64のWasmモジュールをインスタンス化
const memory = new WebAssembly.Memory({
  initial: 1024,   // 1GB(64KBページ × 16384)
  maximum: 16384,  // 16GB
  shared: false,
  index: "i64",    // ← これがMemory64の識別子
});

const { instance } = await WebAssembly.instantiateStreaming(
  fetch("/ml_model.wasm"),
  { env: { memory } }
);

// 4GBを超えるバッファも扱える
instance.exports.load_weights(BigInt(0));

LLM推論エンジンをブラウザで動かす場合、Llama 3 8B(Q4)のモデルウェイトは約4.5GBで、Memory64以前は事実上不可能だった。

例外処理の標準化

従来の言語固有エミュレーションが廃止され、try_table / throw / catch のネイティブ命令が追加された。

❌(旧)setjmp/longjmp ベースのエミュレーション:
  throw 1回 = 複数のWasm命令 + メモリコピー + テーブルルックアップ
  パフォーマンス: ネイティブ比 5〜20倍のオーバーヘッド

✅(新)throw / catch:
  throw 1回 = 数命令
  パフォーマンス: ネイティブ比ほぼ1倍

その他の標準化機能

機能概要
末尾呼び出し最適化 (tail calls)再帰深度が無制限に。Scheme・OCaml・Haskellのコンパイルターゲットとして必須
複数メモリ (multiple memories)1モジュールで複数のメモリ領域を持てる。スタックとヒープを分離管理可能
128-bit SIMD画像処理・暗号化・数値演算の並列実行命令を標準化
relaxed SIMDNaN決定性の制約を緩和してさらに高速な数値演算を可能に

ブラウザサポート状況

ブラウザWasmGCMemory64例外処理
Chrome 120+
Firefox 128+
Safari 18+実験的
Edge 120+

サーバーサイドランタイム(Node.js・Deno・WasmEdge)も主要機能はサポート済みだが、WASIスレッドモデルは依然として策定中。

落とし穴と注意点

スレッドはまだ不完全:ブラウザの SharedArrayBuffer + atomics プロポーザルはあるが、WASI(サーバー側)のスレッドモデルは未確定。std::thread に依存するRustコードをサーバーレスWasmにコンパイルしようとすると詰まる。

Memory64はモバイルで要注意:iOSのSafariは現時点で最大6GBまで(デバイスRAM依存)。Memory64を使うアプリはフォールバックを用意しておくこと。

// Memory64対応チェックと32bitフォールバック
const supportsMemory64 = WebAssembly.validate(new Uint8Array([
  0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00,
  // memory64フラグを含む最小モジュール
]));

const memory = supportsMemory64
  ? new WebAssembly.Memory({ initial: 256, maximum: 4096, index: "i64" })
  : new WebAssembly.Memory({ initial: 256, maximum: 256 });

WasmGCはJS GCと統合される:WeakRefやFinalizationRegistryの動作がWasmGCオブジェクトに影響する。JSとWasm間でオブジェクトを共有する場合、ライフタイム管理に注意が必要。

まとめ

WebAssembly 3.0は「ブラウザでC/Rustを動かす技術」から「あらゆる言語のランタイムをブラウザに持ち込む基盤」へのシフトを意味する。WasmGCによってJava/Kotlin/Dartエコシステムがブラウザに本格参入できるようになり、Memory64によってLLM推論や大規模データ処理が現実的になった。スレッドとWASIの成熟が次のマイルストーンだ。

参考リンク