emscripten-core / emscripten-core/emscripten
Chrome ignoring MAXIMUM_MEMORY=4GB when I run 8 separate instances of WASM module
- Dominant language
- C++
- Stars
- 27.6k
- Forks
- 3.6k
- Avg merge
- 1d 1h
- Merged PRs (30d)
- 105
Description
**Version of emscripten/emsdk:**
```
(system) sevagh@pop-os:~/repos/freemdx-lab/build-wasm$ emcc -v
emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 3.1.5 ()
Ubuntu clang version 13.0.1-2ubuntu2.2
Target: wasm32-unknown-emscripten
Thread model: posix
InstalledDir: /usr/bin
```
**Full link command and output with `-v` appended:**
Relevant part of my CMakeLists.txt file:
```
set(COMMON_LINK_FLAGS "-flto -s ALLOW_MEMORY_GROWTH=1 -s MAXIMUM_MEMORY=4GB -s MODULARIZE=1 -s ASSERTIONS=1")
# demucs executable
set_target_properties(demucs PROPERTIES
LINK_FLAGS "${COMMON_LINK_FLAGS} -s EXPORT_NAME='libdemucs' -s EXPORTED_FUNCTIONS=\"['_malloc', '_free', '_myfunc']\""
)
```
OS:
Pop!_OS 22.04, Linux, AMD64/x86_64 arch
Firefox version: `Mozilla Firefox 120.0.1`
Chrome version: `120.0.6099.109`
## Issue
I have a WASM module that I compile with emscripten/emcc/emcmake, written in C++, where I use the flags `-s ALLOW_MEMORY_GROWTH=1 -s MAXIMUM_MEMORY=4GB`
I use the WebWorker pattern to run my wasm module in a worker.js file. Recently, I wanted to parallelize my workload by launching multiple WebWorkers.
In Firefox, I can use many web workers:
* I have tested 4, 8, 16 workers, where each of the workers uses up to the full 4GB of it's WASM max (resulting in up to 64GB memory used on my computer). This is by design (it's a compute-intensive program)
In Chrome, I can use 4 web workers, where each one uses 4GB of memory:

However, when I use 8 web workers, the 4GB limit seems to be ignored and dropped to 2GB per-module:
```
Service worker active
8main_v3.js:175 updating progress!
3demucs.js:9 emscripten_realloc_buffer: Attempted to grow heap from 1435172864 bytes to 1960050688 bytes, but got error: RangeError: WebAssembly.Memory.grow(): Unable to grow instance memory
emscripten_realloc_buffer @ demucs.js:9
_emscripten_resize_heap @ demucs.js:9
$func208 @ demucs.wasm:0x6a439
$malloc @ demucs.wasm:0x69512
$func120 @ demucs.wasm:0x2f9d6
$func115 @ demucs.wasm:0x2cc9a
$modelDemixSegment @ demucs.wasm:0x5454e
(anonymous) @ demucs.js:9
processAudio @ worker_v2.js:79
(anonymous) @ worker_v2.js:34
Promise.then (async)
onmessage @ worker_v2.js:30
demucs.js:9 Failed to grow the heap from 1435172864 bytes to 1960050688 bytes, not enough memory!
_emscripten_resize_heap @ demucs.js:9
$func208 @ demucs.wasm:0x6a439
$malloc @ demucs.wasm:0x69512
$func120 @ demucs.wasm:0x2f9d6
$func115 @ demucs.wasm:0x2cc9a
$modelDemixSegment @ demucs.wasm:0x5454e
(anonymous) @ demucs.js:9
processAudio @ worker_v2.js:79
(anonymous) @ worker_v2.js:34
Promise.then (async)
onmessage @ worker_v2.js:30
3demucs.js:9 emscripten_realloc_buffer: Attempted to grow heap from 1435172864 bytes to 2460090368 bytes, but got error: RangeError: WebAssembly.Memory.grow(): Unable to grow instance memory
emscripten_realloc_buffer @ demucs.js:9
_emscripten_resize_heap @ demucs.js:9
$malloc @ demucs.wasm:0x69602
$func120 @ demucs.wasm:0x2f9d6
$func115 @ demucs.wasm:0x2cc9a
$modelDemixSegment @ demucs.wasm:0x5454e
(anonymous) @ demucs.js:9
processAudio @ worker_v2.js:79
(anonymous) @ worker_v2.js:34
Promise.then (async)
onmessage @ worker_v2.js:30
demucs.js:9 Failed to grow the heap from 1435172864 bytes to 2460090368 bytes, not enough memory!
_emscripten_resize_heap @ demucs.js:9
$malloc @ demucs.wasm:0x69602
$func120 @ demucs.wasm:0x2f9d6
$func115 @ demucs.wasm:0x2cc9a
$modelDemixSegment @ demucs.wasm:0x5454e
(anonymous) @ demucs.js:9
processAudio @ worker_v2.js:79
(anonymous) @ worker_v2.js:34
Promise.then (async)
onmessage @ worker_v2.js:30
demucs.js:9 Aborted(native code called abort())
abort @ demucs.js:9
_abort @ demucs.js:9
$func62 @ demucs.wasm:0xd959
$func120 @ demucs.wasm:0x2f9fd
$func115 @ demucs.wasm:0x2cc9a
$modelDemixSegment @ demucs.wasm:0x5454e
(anonymous) @ demucs.js:9
processAudio @ worker_v2.js:79
(anonymous) @ worker_v2.js:34
Promise.then (async)
onmessage @ worker_v2.js:30
demucs.js:9 Uncaught (in promise) RuntimeError: Aborted(native code called abort())
at abort (demucs.js:9:31610)
at _abort (demucs.js:9:90635)
at demucs.wasm:0xd959
at demucs.wasm:0x2f9fd
at demucs.wasm:0x2cc9a
at demucs.wasm:0x5454e
at Object._modelDemixSegment (demucs.js:9:32351)
at processAudio (worker_v2.js:79:12)
at worker_v2.js:34:37
abort @ demucs.js:9
_abort @ demucs.js:9
$func62 @ demucs.wasm:0xd959
$func120 @ demucs.wasm:0x2f9fd
$func115 @ demucs.wasm:0x2cc9a
$modelDemixSegment @ demucs.wasm:0x5454e
(anonymous) @ demucs.js:9
processAudio @ worker_v2.js:79
(anonymous) @ worker_v2.js:34
Promise.then (async)
onmessage @ worker_v2.js:30
3demucs.js:9 emscripten_realloc_buffer: Attempted to grow heap from 1435172864 bytes to 1960050688 bytes, but got error: RangeError: WebAssembly.Memory.grow(): Unable to grow instance memory
emscripten_realloc_buffer @ demucs.js:9
_emscripten_resize_heap @ demucs.js:9
$func208 @ demucs.wasm:0x6a439
$malloc @ demucs.wasm:0x69512
$func120 @ demucs.wasm:0x2f9d6
$func115 @ demucs.wasm:0x2cc9a
$modelDemixSegment @ demucs.wasm:0x5454e
(anonymous) @ demucs.js:9
processAudio @ worker_v2.js:79
(anonymous) @ worker_v2.js:34
Promise.then (async)
onmessage @ worker_v2.js:30
demucs.js:9 Failed to grow the heap from 1435172864 bytes to 1960050688 bytes, not enough memory!
...
```
It seems like Chrome is deciding that there are too many total WASM modules, and banning all of them from using more than 2GB of memory. Is this expected behavior?
Is this to help prevent users systems from being overloaded? The total number of workers is a UI option I want to expose to users, so that they should be able to decide that they want to allow my website to run N workers.
Contributor guide
Assessment
This issue has not been assessed yet.