#allocator #memory-allocator #arena-allocator #slab #object #stack-based

obstack

一个快速、基于栈的分配器,可用于任何对象

5 个版本

使用旧的 Rust 2015

0.1.4 2020年9月4日
0.1.3 2017年8月31日
0.1.2 2017年8月31日
0.1.1 2017年8月30日
0.1.0 2017年8月30日

#382 in 内存管理

MIT/Apache

28KB
521

rust-obstack

一个快速的分段栈分配器,支持任何类型的多个对象。

一种类型的竞技场分配器,obstacks 在 Obstack 本身被销毁时一次性释放内存。其优点是分配速度极快:只需指针增加。与类型化的竞技场不同,单个 Obstack 可以包含具有任何数量不同类型的值。

对于 Copy 类型,将值推送到 Obstack 返回一个标准的可变引用

let r: &mut u8 = stack.push_copy(42);
assert_eq!(*r, 42);

Copy 类型不能实现 Drop,因此不需要进行任何操作来释放值,除了释放内存本身,这在 Obstack 本身被丢弃时一次性完成。push_copy() 因此仅限于实现 Copy 的类型。

未实现 Copy 的类型 可能 实现 Drop。由于 Rust 的类型系统没有负的 !Drop 特性,Obstack 有第二个方法 - push() - 不会限制在 Copy 类型上。此方法返回包装类型 Ref<T>,它包装了底层的可变引用。此包装器拥有栈上的值,并确保当包装器超出作用域时调用 drop。基本上 RefBox 的等价物,但使用 Obstack 而不是堆。

在实践中,即使使用了 Ref 包装器,如果底层类型实际上没有实现有意义的 drop 方法,Rust 编译器能够优化掉所有对 drop 的调用,从而获得与 Copy 类型相同的性能;实际的 Ref::drop() 方法是 [inline(always)],以帮助这个过程。这很重要,因为并非所有非 Copy 类型都可以实现 - 尤其是可变引用不能。

Obstack 以分段栈的形式分配内存,由一个或多个连续内存段组成。每次顶部段满了,就会从堆中分配一个新的段。为了确保总分配数保持很小,段以2的幂次形式分配,每个段的大小是前一个的两倍。

一旦分配了段,它就会在整个 Obstack 生命周期中保持稳定,允许直接引用该段中的值;Rust 的生命周期确保这些引用在 Obstack 的生命周期内有效。

基准测试

可以使用以下命令运行一些初步的基准测试:

cargo bench

tl;dr:分配和释放链表的速度大约快10倍。

无运行时依赖