rism-digital/verovio

WebAssembly is `out of memory` with multiple modules on one page

Closed this issue · 3 comments

I have a SPA (using Vue.js, so no page loads where the VerovioModule will reset) in which I use verovio/esm to display multiple scores on one page. Verovio is running in a web worker. I have an overview page with currently ~25 score segments and verovio instances. Although we have a comment in the verovio source code that "only one instance can be created for now" it is possible to still have multiple instances. However, if I filter the scores several times so that new components with verovio instances are removed and added again, at some point I get the following error.

verovio-module-hum.js:9 Uncaught (in promise) RuntimeError: Aborted(RangeError: WebAssembly.instantiate(): Out of memory: Cannot allocate Wasm memory for new instance). Build with -sASSERTIONS for more info.
    at abort (verovio-module-hum.js:9:8239)
    at verovio-module-hum.js:9:10599791

My setup:

  • a new worker is created for every single score
  • in the worker a new VerovioModule is created with createVerovioModule() imported from verovio/wasm-hum.
  • once a score/component is not needed anymore it gets destroyed with onUnmounted(() => toolkit.destroy())

I am not sure whether my setup is not optimal, the verovio toolkit destroy is not working as expected, or this feature needs some improvements in verovio.

Is it wrong to create a new module for each score instance? When I try to use a single module for all instances then I get back wrong scores because the module is not aware of the current state passed with toolkit.loadData and toolkit.setOptions, etc.

Reproduction

I have setup a reproduction repository without web worker: https://github.com/WolfgangDrescher/verovio-out-of-memory
You can also check this directly on StackBlitz: https://stackblitz.com/github/WolfgangDrescher/verovio-out-of-memory?file=src/App.vue

Click "Load 10 scores" button until you get the error WebAssembly.instantiate(): Out of memory in the console. This should happen at the range 80-90.

Are you creating a new toolkit for every score?

The best way, if you're using a web worker, is to treat the web worker as a "server" that hosts a single toolkit. Then it's up to you to clear / reinitialize the Verovio state with every score load. You send a message to the "server" with a score data to render, and it responds with some SVG.

Each instance has a fixed (or at least minimum) size of 250 MB. So 25 instances would be 6.25 GB, which is why you are running out of memory. If the 25 segments are short, then you should definitely use the method that @ahankinson mentions: one instance that produces 25 segments.

Is it wrong to create a new module for each score instance? When I try to use a single module for all instances then I get back wrong scores because the module is not aware of the current state passed with toolkit.loadData and toolkit.setOptions, etc.

You probably avoid that by using renderData, which does option setting, loading and rendering in one step. See https://book.verovio.org/toolkit-reference/toolkit-methods.html#renderdata
A limitation is that it will only render the first page.