4个稳定版本
1.1.2 | 2021年8月3日 |
---|---|
1.1.0 | 2021年1月5日 |
1.0.0 | 2020年8月3日 |
#202 在 调试 分类中
2,415 每月下载量
在 11 crate 中使用
14KB
128 行
assert_no_alloc
此crate提供了一种自定义分配器,允许暂时禁用线程的内存(分配/释放)。如果尝试分配(释放),程序将终止或打印警告。
它使用线程局部存储来存储“禁用标志/计数器”,因此如果底层分配器(目前硬编码为 std::alloc::System
)是线程安全的,则应该是线程安全的。
理由
无分配区域在实时场景(如音频回调)中很重要。分配和释放可能需要不确定的时间,因此有时会导致可听见的故障,因为音频数据未能及时提供服务。
调试此类问题可能很困难,因为这些问题的重复再现很困难。避免此类问题也很困难,因为分配/释放是常见操作,而大多数库没有明确说明某些函数是否可以分配。此外,这甚至可能取决于运行时情况(例如,一个 Vec::push
可能会分配,但如果有足够的空间被 reserve()
,则保证不会分配)。
为了帮助开发者解决这些问题,此crate提供了一种简单的方法来检测所有禁止的分配。
如何使用
首先,配置功能:warn_debug
和 warn_release
将行为从终止程序更改为在 stderr
上打印错误消息。终止对于调试目的很有用,因为它允许您检索堆栈跟踪,而警告则不那么侵入。
请注意,如果您想使用 warn_release
,则需要通过指定 default-features = false
来禁用(默认启用)disable_release
功能。如果设置了 disable_release
(默认情况),则在 --release
模式下构建时,此 crate 将不会执行任何操作。
其次,使用此 crate 提供的分配器。将以下内容添加到 main.rs
use assert_no_alloc::*;
#[cfg(debug_assertions)] // required when disable_release is set (default)
#[global_allocator]
static A: AllocDisabler = AllocDisabler;
第三,将可能不进行分配的代码段包裹起来
assert_no_alloc(|| {
println!("This code can not allocate.");
});
高级用法
可以使用以下方式返回值
let answer = assert_no_alloc(|| { 42 });
可以通过 permit_alloc
覆盖 assert_no_alloc
的效果
assert_no_alloc(|| {
permit_alloc(|| {
// Allocate some memory here. This will work.
});
});
这对于在 assert_no_alloc
上下文中执行代码的测试桩很有用。
在 Drop
时会释放对象的可以包裹在 PermitDrop
中
let foo = PermitDrop::new(
permit_alloc(||
Box::new(...)
)
);
释放 foo
不会触发断言(但释放一个 Box
会)。
assert_no_alloc()
调用可以嵌套,并具有适当的恐慌撤销处理。
请注意,要完全绕过此 crate,例如在发布模式下,您需要同时启用 disable_release
功能标志(默认情况下是启用的)并且不要将 AllocDisabler
注册为 global_allocator
。
示例
请参阅 examples/main.rs 以获取示例。
您可以尝试不同的功能标志
cargo run --example main
-> 4 字节的内存分配失败。已中止(核心转储)cargo run --example main --release --no-default-features
-> 与上面相同。cargo run --example main --features=warn_debug
-> 尝试在一个禁止分配器调用的线程中(分配/释放)内存!如果上面的分配已中止,则此操作将不会执行。cargo run --example main --features=warn_release --release --no-default-features
-> 与上面相同。cargo run --example main --release
甚至不会检查禁止的分配
测试套件
默认功能将导致测试无法编译。使用以下命令运行它们
cargo test --features=warn_debug --tests