26 июля 2026 года команда Bytecode Alliance объявила о долгожданном добавлении в Wasmtime встроенной сборки мусора (GC) и механизма исключений (exceptions) Источник. Это событие — не просто рядовое обновление одного из runtime. Оно знаменует переход WebAssembly от нишевой платформы для компиляции C/C++/Rust к зрелой экосистеме, способной эффективно выполнять управляемые языки вроде Java, C#, Go, Kotlin и Swift. Для разработчиков, которые годами ждали возможности запускать тяжелые бизнес-приложения в изолированном окружении без ручного управления памятью, это настоящий прорыв.
Почему это важно сейчас? До последнего времени WebAssembly оставался «голым» металлом: линейная память, ручное выделение и освобождение, никаких исключений. Любой язык со сборщиком мусора приходилось «тащить» со своим рантаймом — например, компилятор Go вставлял полный GC в бинарник, что увеличивало размер модуля в 2-3 раза. Исключения эмулировались через setjmp/longjmp (для C) или вовсе не поддерживались. Это тормозило внедрение Wasm в серверные приложения, edge-вычисления и мультиязычные микросервисы. Теперь ситуация кардинально меняется.
В чем заключалась проблема?
Отсутствие встроенной сборки мусора
WebAssembly изначально проектировался как низкоуровневая цель компиляции. Его единственная память — это линейная память (linear memory) — непрерывный массив байтов, который управляется вручную. Для языков с автоматическим управлением памятью это означало необходимость либо:
- поставлять собственный сборщик мусора (GC) внутри Wasm-модуля;
- использовать внешний GC через WASI или другие механизмы;
- переписывать критические участки кода на Rust/C.
Первый вариант приводил к раздуванию бинарника (десятки мегабайт) и снижению производительности из-за отсутствия информации о типах на уровне байт-кода. Второй — усложнял развертывание и создавал накладные расходы на взаимодействие с внешней памятью.
Ручная обработка ошибок
Исключения в WebAssembly отсутствовали как концепция. Разработчики использовали коды возврата, глобальные флаги или эмуляцию через setjmp/longjmp (например, в компиляторе Emscripten). Это не только делало код громоздким, но и мешало интеграции с языками, где исключения — ключевой элемент (Java, C#). Эмуляция съедала до 30% производительности в коде с частыми ошибками.
Решение: GC и Exceptions в Wasmtime
Команда Bytecode Alliance реализовала поддержку двух недавно принятых стандартов WebAssembly:
- GC proposal (сборка мусора на основе структурных типов);
- Exception Handling proposal (нативные try/catch на уровне байт-кода).
Как работает новый GC
В стандарт WebAssembly добавлены структурные типы (struct, array, i31 — 31-битные целые, упакованные в ссылку). Объекты размещаются в куче (GC heap), а сборщик мусора работает на уровне runtime, используя информацию о типах из секции type. Wasmtime реализует два режима GC:
- Lanced GC (ленивый) — сборка запускается только при нехватке памяти, паузы минимальны, до 1 мс.
- Concurrent GC (параллельный) — использует несколько потоков для сборки, подходит для серверов с высокой нагрузкой.
Разработчики могут выбирать режим в зависимости от сценария. Важная деталь: GC в Wasmtime не требует модификации компилятора — достаточно, чтобы код на целевом языке использовал новые инструкции. Например, компилятор Kotlin/Native уже генерирует struct.new и ref.cast.
Механизм исключений
Exceptions реализованы как обычные инструкции: try, catch, throw, catch_all. Тип исключения — произвольный ссылочный тип (например, (exception $e i32 i64)). Для обратной совместимости со старыми модулями добавлен полифилл: если код не использует исключения, Wasmtime работает в прежнем режиме. Пользовательские исключения поддерживаются «из коробки».
Результаты и тесты
В статье приводятся результаты бенчмарков для типовых задач. Например, сериализация JSON на Kotlin/Native в Wasmtime с GC показала:
- Производительность: близка к нативной JVM (разница менее 15%).
- Потребление памяти: снижено на 30-40% по сравнению с использованием встроенного GC из Kotlin (за счет того, что Wasmtime GC оптимизирован под конкретный паттерн выделения).
Для серверных приложений на Go (сборка tinygo) пропускная способность (requests/sec) выросла примерно в 2 раза — из-за того, что теперь не нужно тащить полный Go GC в модуль, и сборка мусора стала более эффективной.
| Сценарий | До (без GC) | После (с GC) | Улучшение |
|---|---|---|---|
| JSON-сериализация (Kotlin/Native) | ~100 MB | ~60 MB | -40% памяти |
| HTTP-сервер (Go/tinygo) | 10k rps | 20k rps | +100% пропускная способность |
| Зарядка объектов (Java/GraalVM) | 12 ms (GC пауза) | 3 ms (Lanced) | -75% пауз |
Данные взяты из официального анонса Источник.
Что это значит для индустрии
Мультиязычные микросервисы
Теперь можно компилировать Java- и Go-сервисы в Wasm и запускать их в одном runtime без overhead. Это упрощает стандартизацию деплоя, так как Wasmtime работает и на Linux, и на Windows, и в edge-среде.
Плагины и расширения
Приложения, поддерживающие плагины через WebAssembly (например, Envoy, Kubernetes), наконец-то смогут принимать плагины на Java и C# — достаточно лишь включить GC. Раньше разработчики плагинов были ограничены C/Rust/AssemblyScript.
Образовательные платформы
Для тренажеров и обучающих курсов по языкам с GC (Java, C#, Kotlin) Wasmtime становится идеальной песочницей: безопасное выполнение кода пользователя без установки JDK, с автоматическим управлением памятью. Это открывает новые возможности для онлайн-компиляторов и интерактивных задач.
Технические детали реализации (инсайты из статьи)
Авторы статьи делятся интересными решениями:
- Структурные типы хранятся в отдельной куче, отдельно от линейной памяти. Это позволило не ломать существующий код на C.
- Forward references — типы могут ссылаться друг на друга, что важно для рекурсивных структур (например, деревья).
- Исключения с обработчиками работают по принципу стекового раскручивания, но с возможностью перехвата на любом уровне.
- Для совместимости с wasm-модулями без GC добавлен механизм adapter: модули с GC могут вызывать модули без GC и наоборот, данные копируются автоматически.
Выводы
Добавление сборки мусора и исключений в Wasmtime — это не просто патч, а смена парадигмы. WebAssembly перестает быть «ассемблером для веба» и становится универсальной платформой для любого языка. Для разработчиков это означает:
- меньше ухищрений при портировании кода;
- лучшую производительность за счет оптимизированного GC;
- возможность использовать привычные конструкции (try/catch) даже в изолированной среде.
Команда Bytecode Alliance продолжает активно развивать Wasmtime: в планах — поддержка продолжений (continuations) и улучшенная интеграция с WASI. Но уже сейчас можно начинать экспериментировать: флаг --gc и --exceptions доступны в ночной сборке Wasmtime.
Если вы разрабатываете языки со сборкой мусора или ищете способ безопасно выполнять пользовательский код, присмотритесь к Wasmtime с GC — возможно, это именно то, чего не хватало вашей инфраструктуре. Подробности — в официальной статье Источник.
Комментарии