Qual é a melhor maneira de lidar com fechamentos no WebAssembly com Rust em vez de usar esquecer e vazar memória?

8

Ao fornecer retornos de chamada para JavaScript usando Closures , qual é a melhor maneira de lidar com evitar liberá-los? O guia wasm-bindgen sugere o uso .forget, mas admite que isso é essencialmente vazamento de memória.

Normalmente, armazenaríamos o identificador para depois ser descartado no momento apropriado, mas, por enquanto, queremos que seja um manipulador global; portanto, usamos o forgetmétodo para descartá-lo sem invalidar o fechamento. Observe que isso está vazando memória no Rust, portanto, isso deve ser feito criteriosamente!

Ele sugere armazenar o fechamento até um momento em que é apropriado que ele seja descartado. Na resposta de alexcrichton a uma pergunta anterior , ele menciona ...

[...] se for invocado apenas uma vez, você poderá usar Rc/ RefCellpara soltar o Closureinterior do próprio fechamento (usando algumas travessuras internas de mutabilidade)

Mas ele não fornece um exemplo desse método.

A documentação de fechamento também fornece um exemplo de retorno da referência ao fechamento para o contexto JavaScript para permitir que ele lide quando liberar a referência.

Se cairmos cbaqui, uma exceção será levantada sempre que o intervalo transcorrer. Em vez disso, retornamos nosso identificador de volta para JS para que ele possa decidir quando cancelar o intervalo e desalocar o fechamento.

Eu também imagino que existem maneiras de usar recursos como vidas úteis ou o #[wasm_bindgen] macro em uma função pública para evitar esse problema também, mas estou tendo problemas para descobrir como fazê-lo dessa maneira.

Minha pergunta é: quais são as alternativas ao uso .forgetcom fechamentos que estão sendo passados ​​de volta para o JavaScript a partir do Rust, e posso ver alguns exemplos simples de cada opção em uso?

dinamitado
fonte

Respostas:

1

Recentemente, criei um pequeno aplicativo comercial e fiquei preso por semanas e fiquei realmente empolgado quando consegui esse trabalho. Acabei usando Closure.once_into_js . No entanto, isso também tem a ressalva de que "a única maneira de o FnOnce ser desalocado é chamando a função JavaScript. Se a função JavaScript nunca for chamada, o FnOnce e tudo o que fechar serão vazados". Portanto, se o retorno de chamada for chamado, tudo ficará bem, mas, se não, ainda há um vazamento de memória. Achei o estilo de programação muito bom. Mapeei as funções JavaScript para Rust da seguinte maneira:

#[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())   
    ));
}

E então eu posso usá-lo da Rust no meu aplicativo da seguinte forma:

let callback = move |id| {
};
get_something(&details, callback);

Eu defini os retornos de chamada como funções estáticas de impl e depois movi os valores.

Cameron Taggart
fonte