用 Rust 处理 WebAssembly 中的闭包而不是使用忘记和泄漏内存有啥更好的方法?
Posted
技术标签:
【中文标题】用 Rust 处理 WebAssembly 中的闭包而不是使用忘记和泄漏内存有啥更好的方法?【英文标题】:What's a better way to deal with closures in WebAssembly with Rust instead of using forget and leaking memory?用 Rust 处理 WebAssembly 中的闭包而不是使用忘记和泄漏内存有什么更好的方法? 【发布时间】:2020-05-07 04:53:32 【问题描述】:当使用Closures 向 javascript 提供回调时,有什么更好的方法来避免释放它们? wasm-bindgen guide 建议使用.forget
,但承认这本质上是内存泄漏。
通常我们会存储句柄,以便以后在适当的时候删除,但现在我们希望它是一个全局处理程序,所以我们使用
forget
方法来删除它,而不会使闭包失效。请注意,这会在 Rust 中泄漏内存,因此应谨慎行事!
它暗示将闭包存储到适合删除的时候。在alexcrichton's answer 到a previous question 中,他提到...
[...] 如果它 [...] 只被调用一次,那么您可以使用
Rc
/RefCell
将Closure
放入闭包本身(使用一些内部可变性恶作剧)
但他没有提供这种方法的例子。
Closure documentation 还提供了一个示例,将闭包的引用返回给 JavaScript 上下文,让它处理何时释放引用。
如果我们在此处删除
cb
,它将导致每当间隔过去时引发异常。相反,我们将我们的句柄返回给 JS,这样 JS 就可以决定何时取消间隔并解除分配闭包。
我还想象有一些方法可以在公共函数上使用生命周期或 #[wasm_bindgen]
宏等功能来避免这个问题,但我很难弄清楚如何做到这一点。
我的问题是,除了使用 .forget
和从 Rust 传回 JavaScript 的闭包之外,还有哪些替代方法,我可以看看每个使用中的选项的一些简单示例吗?
【问题讨论】:
【参考方案1】:我最近构建了一个小型商业应用程序,并在这个应用程序上卡了几个星期,当我开始工作时真的很兴奋。我最终使用了Closure.once_into_js。然而,这也有一个警告,“释放 FnOnce 的唯一方法是调用 JavaScript 函数。如果 JavaScript 函数从未被调用,那么 FnOnce 及其关闭的所有内容都会泄漏。”所以如果回调被调用,一切都应该没问题,但如果没有,仍然存在内存泄漏。我发现编程风格非常好。我像这样将 JavaScript 函数映射到 Rust:
#[wasm_bindgen]
fn getSomething(details: &JsValue, callback: JsValue);
pub fn get_something(details: &Details, callback: impl Fn(Option<String>) + 'static)
getSomething(&serde_wasm_bindgen::to_value(details).unwrap(), Closure::once_into_js(move |v: JsValue|
callback(serde_wasm_bindgen::from_value(v).unwrap())
));
然后我可以像这样在我的应用程序中使用 Rust:
let callback = move |id|
;
get_something(&details, callback);
我将回调定义为静态 impl 函数,然后将值移入。
【讨论】:
以上是关于用 Rust 处理 WebAssembly 中的闭包而不是使用忘记和泄漏内存有啥更好的方法?的主要内容,如果未能解决你的问题,请参考以下文章
Rust开发WebAssembly在Html和Vue中的应用后篇
Rust & WebAssembly 翻译系列 为什么选择Rust和WebAssembly?