我什么时候应该调用 wasm-pack 生成的 free() 方法?

Jef*_*nie 4 rust wasm-bindgen wasm-pack

我编写了一些 Rust 代码并使用 wasm-pack 对其进行了编译。free()我在生成的 .d.ts 文件中注意到这些方法:

export class PdfDoc {
  free(): void;
  ...
}
Run Code Online (Sandbox Code Playgroud)

PdfDoc拥有大量内存,高达 1GB,因此当 javascript 代码使用完这些内存时,正确释放所有内存以供重用非常重要。

问题:

  • 我什么时候应该调用这些free()方法?
  • 我需要显式调用它们还是会自动调用它们?
  • 如果我从不打电话给他们会怎样?

我搜索了“wasm-pack free method”,但这些搜索词组合没有找到任何有用的东西。

zan*_*any 5

我想知道同样的事情:使用 wasm-bindgen 时是否需要仔细地将每个new MyStruct()函数与调用配对?free()

我什么时候应该调用这些 free() 方法?

在丢失对 JS 对象包装器实例的最后一个引用之前调用free(),或者如果您使用完该对象,则更早调用。

我需要显式调用它们还是会自动调用它们?

目前,当 JS 对象包装器超出范围时,WASM 分配的内存将不会释放(但下面是弱引用)。

如果我从不打电话给他们会怎样?

WASM 内存丢失,如果没有指针,您将无法恢复它。对于固定或有限数量的较小尺寸的结构来说,这可能不是问题,整个 WASM 内存在卸载页面时被释放。

更详细地说:

查看创建的绑定,我们发现在构造函数中分配的内存不会在其他地方被跟踪,并且如果我们忘记返回的实例(一个将原始指针存储为 的 JS 包装对象ptr),则会有效地丢失内存。

wasm-bindgen 指南还在弱引用支持中暗示了这一点 ,提到目前不支持/实现 TC39 弱引用(2022 年末):

如果没有弱引用,您的 JS 集成可能容易受到 Rust 中内存泄漏的影响,例如:您可能忘记在 JS 对象上调用 .free(),从而留下分配的 Rust 内存。

wasm-bindgen 指南示例WebAudiofree()显示了在重复创建超出范围的对象时防止内存泄漏的用法。最多只剩下一个(活动的)对象,这主要反映了您的用例:通过free()在不再需要对象时和超出范围之前调用来清理对象。

作为仔细内存管理的补充:

使用复制类型时可能需要注意一个设计问题,请考虑:

#[wasm_bindgen]
#[derive(Clone, Copy)]
pub struct Bounds {
    width: usize,
    height: usize,
}
#[wasm_bindgen]
impl Bounds {
    // ...
    #[wasm_bindgen(getter)]
    pub fn width(&self) -> usize {
        self.width
    }
}
#[wasm_bindgen]
pub struct MyThing {
    bounds: Bounds,
    // ...
}
#[wasm_bindgen]
impl MyThing {
    // ...
    #[wasm_bindgen(getter)]
    pub fn bounds(&self) -> Bounds {
        self.bounds
    }
}
Run Code Online (Sandbox Code Playgroud)

这是 Rust 中常见且安全的代码,但如果简单地从 JS 中使用,则会泄漏内存,例如

console.log(`Current width is ${myThing.bounds.width} px`);
Run Code Online (Sandbox Code Playgroud)

您可能想在开发时观察 WASM 内存,例如

console.log(`WASM memory usage is ${wasm.memory.buffer.byteLength} bytes`);
Run Code Online (Sandbox Code Playgroud)

2024 年 2 月更新

正如从 v0.2.91 开始的评论中所指出的,“如果检测到支持,wasm-bindgen 确实会使用 TC39 弱引用提案。在撰写本文时,所有主要浏览器都支持它。” ( wasm-bindgen ) 即如果浏览器支持弱引用,WASM 分配的内存将自动释放。