我有一个用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>,
}

我try 了以下操作来删除数据并释放内存,数据从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.

我也try 了以下方法,但得到了这个错误: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 => {}
    }
}

我怎样才能成功地释放这个内存?

推荐答案

WebAssembly does not offer any instructions to deallocate memory,只有增加分配大小的能力.实际上,这意味着WebAssembly应用程序的最高内存使用量也是permanent内存使用量.

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

我没有知识或能力来测试这一点,但一个开箱即用的 idea 是try 让多个WebAssembly运行时彼此不同.您可以在一个内存中占用大量内存来计算一个相对较小的结果,在WASM运行时之外序列化该结果,然后扔掉它并旋转一个新的结果.这可能只在某些特定的问题领域有用.


将来,WebAssembly可能会增加re个内存大小调整.在MVP发布之前,它被明确删除:

在MVP之后,我们将转向那些分歧的、不能被多重填充的东西,此时增加内存大小更有意义.

感谢alexcrichtonsteveklabnik在Rust Discord中回答这个问题.

Rust相关问答推荐

即使参数和结果具有相同类型,fn的TypId也会不同

Rust中的相互递归特性与默认实现

在没有引用计数或互斥锁的情况下,可以从Rust回调函数内的封闭作用域访问变量吗?

在泛型 struct 的字段声明中访问关联的Conant

在自身功能上实现类似移动的行为,以允许通过大小的所有者进行呼叫(&;mut;self)?

为什么`Vec i64`的和不知道是`Option i64`?

如何获取Serde struct 的默认实例

异步函数返回的future 生存期

为什么AsyncRead在Box上的实现有一个Unpin特征绑定?

为什么 tokio 在以奇怪的方式调用时只运行 n 个任务中的 n-1 个?

有没有办法隐式绑定 let/match 操作的成员?

如何在 Rust 中按 char 对字符串向量进行排序?

为什么传递 option.as_ref 的行为不同于使用匹配块并将内部映射到 ref 自己?

第 7.4 章片段中如何定义 `thread_rng`

使用泛型作为关联类型,没有幻像数据

提取 struct 生成宏中字段出现的索引

Rust:如果我知道只有一个实例,那么将可变borrow 转换为指针并返回(以安抚borrow 判断器)是否安全?

如何断言代码不会在测试中编译?

BigUint 二进制补码

返回引用的返回函数