I'm running wasmer 1.0.0-alpha.3 and recently run into a problem that I'm not sure how to work around. For every instance I crate a new ImportObject capturing an environment with some functions.
The issue is that this environment is never dropped and I can't figure out a way of releasing the memory. My environment is a bit heavier and after running the app for some time I start running out of memory.
I created a minimal example just to illustrate the issue:
use wasmer::{Store, Instance, Module, Exports, ImportObject, Function};
struct Env {
multiplier: i32,
}
impl Drop for Env {
fn drop(&mut self) {
println!("Dropping: {}", self.multiplier);
}
}
fn main() {
let store = Store::default();
let module = Module::new(&store, "(module (import \"env\" \"sum_and_multiply\" (func (param i32 i32) (result i32))))").unwrap();
let env_dropped = Env { multiplier: 1 };
let env_never_dropped = Env { multiplier: 2 };
let f = Function::new_native_with_env(&store, env_never_dropped, sum_and_multiply);
let mut exports = Exports::new();
exports.insert("sum_and_multiply", f);
let mut import_object = ImportObject::new();
import_object.register("env", exports);
let instance = Instance::new(&module, &import_object).unwrap();
}
fn sum_and_multiply(env: &mut Env, a: i32, b: i32) -> i32 {
(a + b) * env.multiplier
}
The output of this app is:
Dropping: 1
As you can see env_dropped is never moved and drops, but env_never_dropped doesn't get it's drop method called. Even after the instance, module and store are all gone.
Ideally I would expect that once there are no more Instances referencing the ImportObject that the resources get released.
It can also be that I structured my app in an unconventional way. Is there maybe a better approach to this?
I think this is related to #1584.
Thanks for the issue, I think this is the same as #1584 too;
I believe once either #1663 or #1625 lands this will be easier to fix as the general ownership of Env is clarified a bit more in those PRs.
We can probably make a solution that's compatible with both of those PRs though
Closing this as #1865 got merged and it fixes the issue. Here is the original snippet, adapted with new requirements:
use wasmer::{Store, Instance, Module, Exports, ImportObject, Function, WasmerEnv};
#[derive(WasmerEnv, Clone)]
struct Env {
multiplier: i32,
}
impl Drop for Env {
fn drop(&mut self) {
println!("Dropping: {:?}", self.multiplier);
}
}
fn main() {
let store = Store::default();
let module = Module::new(&store, "(module (import \"env\" \"sum_and_multiply\" (func (param i32 i32) (result i32))))").unwrap();
let env_dropped = Env { multiplier: 1 };
let env_never_dropped = Env { multiplier: 2 };
let f = Function::new_native_with_env(&store, env_never_dropped, sum_and_multiply);
let mut exports = Exports::new();
exports.insert("sum_and_multiply", f);
let mut import_object = ImportObject::new();
import_object.register("env", exports);
let instance = Instance::new(&module, &import_object).unwrap();
}
fn sum_and_multiply(env: &Env, a: i32, b: i32) -> i32 {
(a + b) * env.multiplier
}
The output is now:
Dropping: 2
Dropping: 2
Dropping: 1
What did I change in the snippet:
Env now has to derive WasmerEnv and Clone&Env instead of a &mut Env (see https://github.com/wasmerio/wasmer/blob/master/examples/imports_function_env.rs to learn how to allow Env mutability)