Weak引用未触发值释放:Wasm Bindgen Drop测试失败
问题原因
- FinalizationRegistry回调的异步性:wasm-bindgen依赖JavaScript的
FinalizationRegistry触发Rust对象的Drop逻辑。当JS对象被垃圾回收后,FinalizationRegistry的回调是异步调度的,不会在调用window.gc()后立即执行。你的测试在调用gc()后立刻断言,此时Drop逻辑还未执行,导致断言失败。 - Chrome Headless的GC配置缺失:默认情况下Chrome Headless可能未启用
window.gc()的暴露,或GC策略不会立即回收无引用对象,导致GC调用未生效。 - 潜在的引用残留:测试运行环境(如wasm-bindgen-test的运行时)可能意外保留了JS对象的引用,阻碍垃圾回收触发。
解决办法
1. 修改测试代码,等待异步Drop回调执行
利用Promise和异步等待逻辑,确保Drop完成后再执行断言:
use std::sync::atomic::{AtomicBool, Ordering}; use std::mem; use wasm_bindgen::JsValue; use wasm_bindgen_test::{wasm_bindgen_test, wasm_bindgen_test_configure}; use wasm_bindgen_futures::JsFuture; use js_sys::{Promise, Function}; wasm_bindgen_test_configure!(run_in_browser); // 将static变量移到函数外部,避免测试状态污染 static DROPPED: AtomicBool = AtomicBool::new(false); struct SetOnDrop; impl Drop for SetOnDrop { fn drop(&mut self) { let is_dropped = DROPPED.swap(true, Ordering::AcqRel); assert!(!is_dropped); } } #[wasm_bindgen] struct WasmSetOnDrop(SetOnDrop); #[wasm_bindgen_test] async fn test_drop() { // 重置状态,确保每次测试都是干净的 DROPPED.store(false, Ordering::Release); let value = WasmSetOnDrop(SetOnDrop); let value = JsValue::from(value); // 第一次GC验证对象未被提前回收 js_sys::eval("window.gc()").expect("Unable to call `window.gc`"); assert!(!DROPPED.load(Ordering::Acquire), "Value was dropped early"); // 丢弃Rust侧的JS引用 mem::drop(value); // 触发GC js_sys::eval("window.gc()").expect("Unable to call `window.gc`"); // 创建Promise,轮询等待Drop完成 let promise = Promise::new(&mut |resolve, _reject| { let check = move || { if DROPPED.load(Ordering::Acquire) { resolve.call1(&JsValue::undefined(), &JsValue::from(true)).unwrap(); } else { // 每隔10ms检查一次,最多等待5秒 web_sys::window().unwrap().set_timeout_with_callback_and_timeout_and_arguments_0( &Function::new_no_args(&check), 10, ).unwrap(); } }; check(); }); // 等待Promise完成,超时则测试失败 JsFuture::from(promise).await.expect("Timeout waiting for drop"); // 最终断言 assert!(DROPPED.load(Ordering::Acquire), "Value was not dropped"); }
2. 完善Chrome Headless运行参数
修改测试命令,添加Chrome启动参数确保GC可用且行为可靠:
WASM_BINDGEN_WEAKREF=1 WASM_BINDGEN_EXTERNREF=1 wasm-pack test --chrome --headless -- --chrome-arg=--js-flags="--expose-gc" --chrome-arg=--enable-precise-memory-info
3. 排除环境引用残留
- 确保测试对象未被赋值给全局变量(如
window属性) - 避免测试代码中其他可能持有JS对象引用的逻辑
内容的提问来源于stack exchange,提问作者Filipe Rodrigues
相关产品推荐
相关产品推荐

