忘れてメモリリークを使用する代わりに、Rustを使用してWebAssemblyでクロージャを処理するより良い方法は何ですか?


8

Closuresを使用してJavaScriptにコールバックを提供するとき、それらを解放しないように対処するためのより良い方法は何ですか?wasm-bindgenガイドを使用して示唆し.forget、それは本質的にメモリをリークしていることを認めています。

通常は、後で適切なタイミングでドロップされるようにハンドルを格納しますが、今のところ、それをグローバルハンドラーにして、forgetメソッドを使用して、クロージャーを無効にすることなくそれをドロップします。これはRustでメモリリークを起こしているので注意してください。

これは、ドロップするのが適切になるまでクロージャーを保管することを示します。でalexcrichtonの答え、前の質問に、彼は言及します...

[...]一度しか呼び出されない場合は、[ Rc/] RefCellを使用しClosureて、クロージャー自体の内部をドロップできます(内部の可変性シェナンを使用します)。

しかし、彼はこの方法の例を提供していません。

閉鎖のマニュアルには、参照を解放するときに処理させるためにはJavaScriptコンテキストに閉鎖への参照を返す例を示します。

cbここにドロップすると、間隔が経過するたびに例外が発生します。代わりに、私たちは、返し JSが間隔をキャンセルし、閉鎖を解放する際に決めることができるように私たちのハンドルバックはJSに。

また#[wasm_bindgen]、この問題を回避するために、パブリック関数のライフタイムやマクロなどの機能を使用する方法もあると思いますが、その方法を理解するのに苦労しています。

私の質問は、.forgetRustから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);

コールバックを静的実装関数として定義し、値を移動しました。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.