我希望通过定期记录WASM堆的已用部分的大小来检测内存泄漏.最简单的方法是什么?

我以为《Rust and WebAssembly》一书对此有一些建议,但我找不到.

推荐答案

正如注释中所解释的,您可以通过JavaScript获得WASM(WebAssembly.Memory.prototype.buffer.byteLength)中的总内存使用量.这永远不会缩小,但如果它不断增长,那么你可能有泄漏.你可以通过wasm_bindgen::memory()获得WebAssembly.Memory实例,其余的可以通过wasm_bindgen完成:

fn get_current_allocated_bytes() -> u64 {
    #[wasm_bindgen]
    extern "C" {
        type Memory;
        #[wasm_bindgen(method, getter)]
        fn buffer(this: &Memory) -> MaybeSharedArrayBuffer;

        type MaybeSharedArrayBuffer;
        #[wasm_bindgen(method, getter = byteLength)]
        fn byte_length(this: &MaybeSharedArrayBuffer) -> f64;
    }

    wasm_bindgen::memory()
        .unchecked_into::<Memory>()
        .buffer()
        .byte_length() as u64
}

如果你想要一个更高性能的实现(这会相当慢),或者如果你想要一个更精确的度量(如前所述,这不会计算释放),你可以实现一个全局分配器:

use std::alloc::{GlobalAlloc, Layout, System};
use std::sync::atomic::{AtomicIsize, Ordering};

struct CountingAllocator<A> {
    inner: A,
    allocated_now: AtomicIsize,
}

impl<A> CountingAllocator<A> {
    const fn new(inner: A) -> Self {
        Self {
            inner,
            allocated_now: AtomicIsize::new(0),
        }
    }

    fn allocated_now(&self) -> usize {
        self.allocated_now
            .load(Ordering::Relaxed)
            .try_into()
            .unwrap_or(0)
    }
}

unsafe impl<A: GlobalAlloc> GlobalAlloc for CountingAllocator<A> {
    unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
        self.allocated_now
            .fetch_add(layout.size() as isize, Ordering::Relaxed);
        self.inner.alloc(layout)
    }

    unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
        self.allocated_now
            .fetch_sub(layout.size() as isize, Ordering::Relaxed);
        self.inner.dealloc(ptr, layout);
    }

    unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
        self.allocated_now
            .fetch_add(layout.size() as isize, Ordering::Relaxed);
        self.inner.alloc_zeroed(layout)
    }

    unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
        self.allocated_now.fetch_add(
            new_size as isize - layout.size() as isize,
            Ordering::Relaxed,
        );
        self.inner.realloc(ptr, layout, new_size)
    }
}

#[global_allocator]
static ALLOCATOR: CountingAllocator<System> = CountingAllocator::new(System);

然后调用ALLOCATOR.allocated_now()以检索当前分配的字节的确切数目.

Rust相关问答推荐

为什么类型需要在这个代码中手动指定,在rust?

展开枚举变量并返回所属值或引用

在Rust中,在实现特征`Display`时,如何获取调用方指定的格式?

如何将单个 struct 实例与插入器一起传递到Rust中的映射

我们能确定Rust会优化掉Clone()吗?如果它会立即掉落?

解析程序无法在Cargo 发布中 Select 依赖版本

如何迭代存储在 struct 中的字符串向量而不移动它们?

闭包返回类型的生命周期规范

Rust 为什么被视为borrow ?

如何基于常量在Rust中跳过一个测试

Sized问题的动态调度迭代器Rust

没有明确地说return会产生错误:match arms have incompatible types

如何刷新 TcpStream

了解 Rust 闭包:为什么它们持续持有可变引用?

Rust 引用元组和引用元组

改变不实现克隆的 dioxus UseState struct

如何解析 Rust 中的 yaml 条件字段?

如果我不想运行析构函数,如何移出具有析构函数的 struct ?

Rust 生命周期:不能在方法内重新borrow 可变字段

如何重写这个通用参数?