fix(wasm): bound warm-instance linear memory by recycling#369
Open
skhaz wants to merge 1 commit into
Open
Conversation
Why: The inline pool keeps one warm component instance alive across calls; WASM linear memory only ever grows, so each call's guest allocations accumulate without bound (~62KB/call for an image-heavy PDF; RSS climbing past 6GB and the Go heap past 2GB under sustained conversion). What: Recycle the warm instance after recycleWarmInstanceAfter (512) synchronous calls: close it so the next call instantiates a fresh one and reclaims the linear memory, keeping the fast warm path for the common case. Re-instantiation is now safe because wasm-runtime is bumped to a version that rebuilds the per-instance import bridges, so a fresh instance no longer reuses a bridge bound to a closed instance's core. Adds a regression test asserting the instance is recycled at the threshold.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
A reused warm WASM component instance (per inline worker) keeps its linear memory alive across calls; WASM linear memory only ever grows, so each conversion's guest allocations accumulate without bound. Under sustained document conversion, RSS climbed past 6 GB and the Go heap past 2 GB (~62 KB retained per call for an image-heavy PDF).
What
Recycle the warm instance after
recycleWarmInstanceAfter(512) synchronous calls: close it so the next call instantiates a fresh one and reclaims the linear memory, while keeping the fast warm path for the common case. Re-instantiation is now safe becausewasm-runtimeis bumped to a version that rebuilds the per-instance import bridges, so a fresh instance no longer reuses a bridge bound to a closed instance's core.runtime/wasm/engine/process.go:warmCallscounter + recycle instepSync.go.mod: bumpwasm-runtime→cc678f6(per-instance bridge rebuild).TestProcessRecyclesWarmInstanceAfterThreshold.Validation (10,000× sustained convert loop)
alloc)heap_objectsgolangci-lintclean; full./runtime/wasm/...suite green under-race; fullmake test-runtimegreen; independent code review verdict: ship.Follow-up (not in this PR)
Re-instantiation recompiles the synthetic bridge and its wazero
CompiledModuleis not freed onClose(~42 objects per re-instantiation). Recycling amortizes this to ~0.07 obj/call (negligible), but a complete fix would free the bridgeCompiledModuleonCloseinwasm-runtime.recycleWarmInstanceAfter(512) could be made env-tunable.