#分配器 #实时 #线程安全 #音频 #线程局部存储 #内存管理

assert_no_alloc

自定义Rust分配器,允许暂时禁用线程的内存(分配/释放)。如果尝试分配(释放),程序将终止或打印警告。

4个稳定版本

1.1.2 2021年8月3日
1.1.0 2021年1月5日
1.0.0 2020年8月3日

#202调试 分类中

Download history 438/week @ 2024-03-14 348/week @ 2024-03-21 616/week @ 2024-03-28 385/week @ 2024-04-04 542/week @ 2024-04-11 349/week @ 2024-04-18 416/week @ 2024-04-25 323/week @ 2024-05-02 610/week @ 2024-05-09 596/week @ 2024-05-16 508/week @ 2024-05-23 604/week @ 2024-05-30 620/week @ 2024-06-06 690/week @ 2024-06-13 638/week @ 2024-06-20 322/week @ 2024-06-27

2,415 每月下载量
11 crate 中使用

BSD-1-Clause

14KB
128

assert_no_alloc

此crate提供了一种自定义分配器,允许暂时禁用线程的内存(分配/释放)。如果尝试分配(释放),程序将终止或打印警告。

它使用线程局部存储来存储“禁用标志/计数器”,因此如果底层分配器(目前硬编码为 std::alloc::System)是线程安全的,则应该是线程安全的。

文档 @ docs.rs, crates.io

理由

无分配区域在实时场景(如音频回调)中很重要。分配和释放可能需要不确定的时间,因此有时会导致可听见的故障,因为音频数据未能及时提供服务。

调试此类问题可能很困难,因为这些问题的重复再现很困难。避免此类问题也很困难,因为分配/释放是常见操作,而大多数库没有明确说明某些函数是否可以分配。此外,这甚至可能取决于运行时情况(例如,一个 Vec::push 可能会分配,但如果有足够的空间被 reserve(),则保证不会分配)。

为了帮助开发者解决这些问题,此crate提供了一种简单的方法来检测所有禁止的分配。

如何使用

首先,配置功能:warn_debugwarn_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

无运行时依赖

功能