Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I free memory allocated by Rust code exposed in WebAssembly?

I have a web application written in Rust and wasm-bindgen that needs to store state. The state is stored like this:

lazy_static! {
    static ref ID_TO_DATA: Mutex<HashMap<u32, Data>> = Mutex::new(HashMap::new());
}

pub struct Data {
    pub coder_id: u16,
    pub bools: Vec<bool>,
    pub ints: Vec<i32>,
    pub strings: Vec<String>,
}

I attempted the following to remove the data and free the memory, and the data is removed from the HashMap and no errors are reported:

#[wasm_bindgen]
pub fn remove_data(id: u32) {
    match ID_TO_DATA.lock().unwrap().remove(&id) {
        Some(data) => {
            std::mem::drop(data);
        }
        None => {}
    }
}

However, the memory used by the browser tab never drops (using Chrome 67). I used Windows' Task Manager and watched the memory grow to almost 2GB for the relevant process/tab, and then after my program removed all the entries, I waited a minute and the memory was still at almost 2GB.

I also tried the following, but got this error: RuntimeError: memory access out of bounds

#[wasm_bindgen]
pub fn remove_data(id: u32) {
    match ID_TO_DATA.lock().unwrap().remove(&id) {
        Some(mut data) => {
            unsafe {
                std::ptr::drop_in_place(&mut data);
            }
        }
        None => {}
    }
}

How can I successfully free this memory?

like image 981
Adam R Avatar asked Jul 26 '18 17:07

Adam R


1 Answers

WebAssembly does not offer any instructions to deallocate memory, there is only the ability to increase the allocated size. Practically speaking, this means that the peak memory usage of your WebAssembly application is also the permanent memory usage.

For a given problem, it may be possible to tweak your algorithm to reduce the peak amount of memory.

I don't have the knowledge or ability to test this, but one out-of-the-box idea would be to try and have multiple WebAssembly runtimes distinct from each other. You could chew up a lot of memory in one to compute a relatively small result, serialize that result outside of the WASM runtime, then throw it away and spin up a new one. This is likely only to be useful in certain specific problem domains.


In the future, memory resizing may be re-added to WebAssembly. It was explicitly removed before the MVP release:

After the MVP, we are moving to things that diverge and cannot be polyfilled, and memory resizing makes more sense to add at that point in time.

  • Remove memory resizing from the MVP (294)
  • Only allow memory growth in MVP (389)

Thanks to alexcrichton and steveklabnik for answering this question in the Rust Discord.

like image 53
Shepmaster Avatar answered Nov 06 '22 12:11

Shepmaster