Quick answer: Build with -s ALLOW_MEMORY_GROWTH=1, set a generous INITIAL_MEMORY, cap with MAXIMUM_MEMORY, and re-acquire HEAP* typed-array views after any growth.

An Emscripten-built game runs for a while, then crashes with “Cannot enlarge memory arrays” or a detached ArrayBuffer error.

Allow Growth

emcc ... -s ALLOW_MEMORY_GROWTH=1 \
        -s INITIAL_MEMORY=268435456 \
        -s MAXIMUM_MEMORY=1073741824

Without ALLOW_MEMORY_GROWTH, the WASM heap is fixed — the first allocation past INITIAL_MEMORY crashes. With it, the heap can grow up to MAXIMUM_MEMORY.

Set a Realistic Initial Size

Growth isn’t free — it reallocates the whole buffer. Profile your real peak usage and set INITIAL_MEMORY close to it so growth rarely (or never) happens at runtime.

Re-Acquire HEAP Views After Growth

When the heap grows, the underlying ArrayBuffer is replaced — any cached HEAPU8, HEAPF32, etc. reference is now detached. Don’t cache them across frames; re-read Module.HEAPU8 after any call that might allocate.

Cap the Maximum

Set MAXIMUM_MEMORY so a leak fails loudly at a known ceiling instead of consuming the whole tab and getting OOM-killed by the browser unpredictably.

Verifying

Play a long session through memory-heavy scenes. The heap grows once or twice (or not at all with a good initial size) and never crashes. Detached-buffer errors are gone.

“Allow growth, size the initial heap well, cap the max, and never cache HEAP views.”

Mobile browser tabs have tight memory budgets — test your MAXIMUM_MEMORY on a real phone, not just desktop Chrome.