Description
Describe the bug
When using a single long running headless engine in combination with many loads from a file system cache, the memory usage increases constantly. If modules are just instantiated from in-memory Module instances, this does not happen. This was observed by CosmWasm users.
The issue can be reproduced using the following adapted Wasmer example: master...webmaster128:demo-memory-growth. What this is doing is:
- Compile a module and store it to disk in a compiling engine. Singlepass/Cranelift makes no difference. Drop that engine.
- Create a headless engine for executing modules
- Load modules from disk and drop them later
Steps to reproduce
- Checkout https://github.com/webmaster128/wasmer/tree/demo-memory-growth
- Run
cargo run --example engine-headless --release --features "cranelift"
in the repo root
Expected behavior
The memory usage of the example stays below a reasonable bound because the deserialized Module
s are dropped
Actual behavior
Running the above example leads to the following memory profile:
A few notes here:
- This slows allocation tracking by
xcrun xctrace record --template 'Allocations' --launch ./target/release/examples/engine-headless
- This run peaks at 27GB memory usage, but we can get arbitrarily high by increasing the number of module deserializations
- Where the blue line is the systems starts to swap
- There is a 5s pause at the beginning and end of the program. Once the runtime engine is dropped, memory is low again.
A different memory profiling approach shows the route through which the majority of allocations are created:

Additional context
OS:
- reproducible example is developed on ARM-based macOS
- same problem occurs on x86_64-based GNU Linux systems
Wasmer version:
commit 04600507844bae978239531c8e6265d410aefe6d (HEAD -> master, tag: v4.2.5, wasmerio/master, wasmerio/HEAD, origin/master)
Merge: 1b803c93a7 04c49aee4e
Author: Arshia001 <[email protected]>
Date: Sat Dec 23 13:30:03 2023 +0400
Merge pull request #4374 from wasmerio/release-4.2.5
Release 4.2.5
This problem started since we refactored our caching solution such that we only use a single long living runtime engine instead of having to cache (Module, Engine) pairs. It might have been in Wasmer for a long time.