JavaScript ArrayBuffer "detaches" 当通过 WASM 构造一个新的 Rust Vec 时
JavaScript ArrayBuffer "detaches" when constructing a new Rust Vec via WASM
基本思想是返回一个指针,然后在每个视频帧创建Vec
后使用指针显示图像:
JavaScript:
var ptr = exports.alloc(size);
let bytes = new Uint8ClampedArray(exports.memory.buffer, ptr, size);
let image = new ImageData(bytes, 320, 240);
function tick() {
requestAnimationFrame(tick);
ctx.drawImage(video, 0, 0, width, height);
let imageData = ctx.getImageData(0, 0, width, height).data;
bytes.set(imageData);
exports.create_vector();
ctx.putImageData(img, 0, 0);
}
生锈:
#[no_mangle]
pub extern "C" fn alloc(capacity: usize) -> *mut c_void {
let mut buf = Vec::with_capacity(capacity);
let ptr = buf.as_mut_ptr();
mem::forget(buf);
return ptr as *mut c_void;
}
#[no_mangle]
pub extern "C" fn create_vector() {
let _: Vec<u8> = Vec::with_capacity(320 * 240);
}
错误信息如下:
Chrome:
Uncaught TypeError: Cannot perform %TypedArray%.prototype.set on a detached ArrayBuffer
at Uint8ClampedArray.set (<anonymous>)
at tick
野生动物园:
This webpage was reloaded because a problem occurred
Mozilla:
DOMException: "An attempt was made to use an object that is not, or is no longer, usable"
TypeError: Underlying ArrayBuffer has been detached from the view
罪魁祸首似乎是:
let bytes = new Uint8ClampedArray(exports.memory.buffer, ptr, size);
// ...
exports.create_vector();
// ...
即,当我在调用 exports.create_vector
后再次尝试使用 ptr
时浏览器崩溃。
这里出了什么问题?有解决办法吗?
当您分配一个新的缓冲区,而 WASM "process" 没有为其分配足够的内存时,浏览器将分配一个新的、更大的缓冲区,并将所有数据从旧位置复制到其中。它在 WASM 解释器内部是非常透明的,但是所有传递给 JavaScript 的指针(你用它构造 Uint8ClampedArray
)都会失效。据我所知有两种解决方案:
- 初始化时在 WASM "process" 中分配足够的内存并立即解除分配,这样只要内存使用量低于所选大小,指针就不会失效。
- 跟踪传递给 JavaScript 的缓冲区和 "renew" 此类错误的指针。
基本思想是返回一个指针,然后在每个视频帧创建Vec
后使用指针显示图像:
JavaScript:
var ptr = exports.alloc(size);
let bytes = new Uint8ClampedArray(exports.memory.buffer, ptr, size);
let image = new ImageData(bytes, 320, 240);
function tick() {
requestAnimationFrame(tick);
ctx.drawImage(video, 0, 0, width, height);
let imageData = ctx.getImageData(0, 0, width, height).data;
bytes.set(imageData);
exports.create_vector();
ctx.putImageData(img, 0, 0);
}
生锈:
#[no_mangle]
pub extern "C" fn alloc(capacity: usize) -> *mut c_void {
let mut buf = Vec::with_capacity(capacity);
let ptr = buf.as_mut_ptr();
mem::forget(buf);
return ptr as *mut c_void;
}
#[no_mangle]
pub extern "C" fn create_vector() {
let _: Vec<u8> = Vec::with_capacity(320 * 240);
}
错误信息如下:
Chrome:
Uncaught TypeError: Cannot perform %TypedArray%.prototype.set on a detached ArrayBuffer
at Uint8ClampedArray.set (<anonymous>)
at tick
野生动物园:
This webpage was reloaded because a problem occurred
Mozilla:
DOMException: "An attempt was made to use an object that is not, or is no longer, usable"
TypeError: Underlying ArrayBuffer has been detached from the view
罪魁祸首似乎是:
let bytes = new Uint8ClampedArray(exports.memory.buffer, ptr, size);
// ...
exports.create_vector();
// ...
即,当我在调用 exports.create_vector
后再次尝试使用 ptr
时浏览器崩溃。
这里出了什么问题?有解决办法吗?
当您分配一个新的缓冲区,而 WASM "process" 没有为其分配足够的内存时,浏览器将分配一个新的、更大的缓冲区,并将所有数据从旧位置复制到其中。它在 WASM 解释器内部是非常透明的,但是所有传递给 JavaScript 的指针(你用它构造 Uint8ClampedArray
)都会失效。据我所知有两种解决方案:
- 初始化时在 WASM "process" 中分配足够的内存并立即解除分配,这样只要内存使用量低于所选大小,指针就不会失效。
- 跟踪传递给 JavaScript 的缓冲区和 "renew" 此类错误的指针。