You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
wasm: linear memory declared at 3.3GB, where the same program built with Go declares 29MB #5599
A wasm module I build declares 3328 MB of linear memory. The same source built with standard Go declares 29 MB — a factor of 115. Reading memory.buffer.byteLength immediately after instantiateStreaming, before go.run, already reports 3328 MB, so this is declared rather than grown, and no Go code has run to allocate it.
It matters beyond the footprint: at 3.3GB, ordinary addresses sit above 2GB, which puts every syscall/js call into #5095 (addresses arriving as signed i32). The terminals in my program stay blank while everything around them draws, one uncaught RangeError per call.
What it is not
Not the collector.-gc=precise produces byte-identically 3328 MB. Consistent with the memory never having been allocated by the GC.
Not -stack-size. I pass -stack-size 1MB; on a small binary that accounts for about 6MB (2MB without it, 8MB with).
Not any one dependency. Built individually as package main importing only that package, with the same flags:
import
declared
charmbracelet/glamour (pulls goldmark, chroma)
11 MB
gdamore/tcell/v2
1 MB
rivo/tview
1 MB
gdamore/proxima5
2 MB
xterm-go (a VT emulator)
1 MB
two smaller DOM packages
0 MB
all of them, in one program
3328 MB
So it appears to be emergent from the combination rather than attributable to a package, which is why I have not been able to reduce it further. Happy to bisect against a hypothesis if there is one worth testing — each build takes about 17 minutes, so I would rather aim than sweep.
Measuring it
// in wasm_exec.js constructorglobalThis.__memlog=()=>this._inst.exports.memory.buffer.byteLength;
Flags: -no-debug -stack-size 1MB -interp-timeout 10m. The stack size is needed because the default overflows in regexp/syntax.Simplify when expanding a bounded repeat ({1,256} in goldmark's linkify pattern) — the overflow does not fault, it corrupts, and regexp then panics at startup on a case it treats as unreachable. The interp timeout is needed because the default three minutes is not enough for goldmark.
@0pcom I couldn’t reproduce the 3.3GB initial memory size with glamour, tcell, and tview together, but I think the measurement might be misleading. this._inst is set inside go.run, which runs _start synchronously before returning. Not awaiting it doesn’t mean no Go code has run.
Could you check instance.exports.memory.buffer.byteLength directly before calling go.run? Or share the .wasm so we can check its declared memory size?
Also worth trying current dev. #5575 fixed false GC retention from globals, including with -gc=precise, after 0.42.0. I could reproduce excessive growth with a separate allocation test on 0.41.1, but not current dev.
You are right about the measurement. this._inst is only set inside go.run, so my snippet could not have read the size before Go code ran, and the 3328 MB was grown rather than declared.
I can't share that .wasm or rebuild it, because the program has since been reworked and no longer imports glamour, tview or proxima5. Reading the memory section of a larger module instead, skywire built with 0.44.0-dev (an 89 MB .wasm), declares 409 pages, which is 25.6 MiB. So I have nothing that shows a large declared size on current dev. I'm closing this, and I'll reopen with a module if I see it again.
Activity
jakebailey commentedon Sep 27, 2026
@0pcom I couldn’t reproduce the 3.3GB initial memory size with glamour, tcell, and tview together, but I think the measurement might be misleading.
this._instis set insidego.run, which runs_startsynchronously before returning. Not awaiting it doesn’t mean no Go code has run.Could you check
instance.exports.memory.buffer.byteLengthdirectly before callinggo.run? Or share the.wasmso we can check its declared memory size?Also worth trying current dev. #5575 fixed false GC retention from globals, including with
-gc=precise, after 0.42.0. I could reproduce excessive growth with a separate allocation test on 0.41.1, but not current dev.0pcom commentedon Oct 14, 2026
You are right about the measurement.
this._instis only set insidego.run, so my snippet could not have read the size before Go code ran, and the 3328 MB was grown rather than declared.I can't share that .wasm or rebuild it, because the program has since been reworked and no longer imports glamour, tview or proxima5. Reading the memory section of a larger module instead, skywire built with 0.44.0-dev (an 89 MB .wasm), declares 409 pages, which is 25.6 MiB. So I have nothing that shows a large declared size on current dev. I'm closing this, and I'll reopen with a module if I see it again.