如何释放由 WebAssembly 暴露的 Rust 代码分配的内存?

18

我有一个用Rust和wasm-bindgen编写的Web应用程序需要存储状态。状态是这样存储的:

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>,
}

我尝试了以下方法来删除数据并释放内存,HashMap中的数据已被删除,且未报告任何错误:


#[wasm_bindgen]
pub fn remove_data(id: u32) {
    match ID_TO_DATA.lock().unwrap().remove(&id) {
        Some(data) => {
            std::mem::drop(data);
        }
        None => {}
    }
}
然而,浏览器选项卡使用的内存从不下降(使用Chrome 67)。我使用了Windows任务管理器并观察到相关进程/选项卡的内存增长近2GB,然后在我的程序删除所有条目后等待了一分钟,内存仍然接近2GB。我还尝试了以下操作,但收到了此错误: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 => {}
    }
}

我该如何成功释放这段内存?


3
你能展示一下你如何测量浏览器中的内存使用情况吗?你可能还想了解std::mem::drop是如何实现的,以避免误用。 - E net4
2
正如 E_net4 所暗示的那样,您的 remove_data 方法可以编写为 ID_TO_DATA.lock().unwrap().remove(&id);。没有调用 drop,也没有 match - Shepmaster
3
通常情况下(不仅限于 Rust),释放的内存不会返回给操作系统,而是返回给程序的分配器。例如请参见 Python memory releasing very slowly, Linux Allocator Does Not Release Small Chunks of Memory,和 In Perl, how can I release memory to the operating system? - trent
感谢@trentcl,我想再试几次添加/删除数据的多个周期,虽然浏览器内存从未显着下降,但它不会继续增长,所以我只能假设WebAssembly正在重用内存。这对我的需求已经足够了。 - Adam R
1个回答

20

WebAssembly没有提供任何释放内存的指令, 只能增加分配的大小。实际上,这意味着您的WebAssembly应用程序的峰值内存使用量也是永久性内存使用量。

对于给定的问题,可能可以调整算法以减少峰值内存量。

我没有测试这个的知识或能力,但一个创新的想法是尝试拥有多个彼此不同的WebAssembly运行时。您可以在其中一个中占用大量内存来计算相对较小的结果,将该结果序列化到WASM运行时之外,然后丢弃它并启动一个新的运行时。这只有在某些特定的问题领域中才有用。


在未来,内存调整可能会重新添加到WebAssembly中。在MVP发布之前,它被明确地删除了:
“在MVP之后,我们将转向不能够进行polyfill的事物,并且在那个时候添加内存调整更有意义。” 从MVP中删除内存调整(294) 只允许内存增长在MVP中(389) 感谢alexcrichtonsteveklabnik在Rust Discord中回答这个问题。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接