36个稳定版本
3.16.0 | 2024年4月8日 |
---|---|
3.15.4 | 2024年3月7日 |
3.15.3 | 2024年2月22日 |
3.14.0 | 2023年9月14日 |
1.1.0 | 2018年11月28日 |
在内存管理中排名第1
每月下载量5,477,274
在34,126个crates(直接使用153个)中使用
335KB
3.5K SLoC
bumpalo
bumpalo是一个为Rust设计的快速bump分配竞技场。
bump分配
bump分配是一种快速但有限的分配方法。我们有一块内存,并在其中维护一个指针。每当我们要分配一个对象时,我们会快速检查我们是否有足够的容量来分配该对象,然后根据对象的大小更新指针。**就这样!**
bump分配的缺点是没有一种通用的方法来处理单个对象的释放或回收不再使用的对象的内存区域。
这些权衡使bump分配非常适合**面向阶段**的分配。也就是说,一组将在同一程序阶段分配、使用然后可以作为一个组一起释放的对象。
大规模释放,但没有Drop
要一次性释放竞技场中的所有对象,我们可以简单地将bump指针重置回竞技场内存块的起始位置。这使得大规模释放**极其**快速,但不会调用分配对象的Drop
实现。
然而: 可以使用
bumpalo::boxed::Box<T>
来包裹在Bump
区域分配的T
值,并在Box<T>
包装器超出作用域时调用T
的Drop
实现方式。这与std::boxed::Box
的操作类似,只不过不会释放其支持内存。
当内存块已满时会发生什么?
此实现将从全局分配器分配新的内存块,然后开始在此新内存块中进行 bump 分配。
示例
use bumpalo::Bump;
use std::u64;
struct Doggo {
cuteness: u64,
age: u8,
scritches_required: bool,
}
// Create a new arena to bump allocate into.
let bump = Bump::new();
// Allocate values into the arena.
let scooter = bump.alloc(Doggo {
cuteness: u64::max_value(),
age: 8,
scritches_required: true,
});
// Exclusive, mutable references to the just-allocated value are returned.
assert!(scooter.scritches_required);
scooter.age += 1;
集合
当 "collections"
cargo 功能启用时,在 collections
模块中可用的是 std
库一些集合的分支。这些集合类型被修改为在 bumpalo::Bump
区域内分配空间。
#[cfg(feature = "collections")]
{
use bumpalo::{Bump, collections::Vec};
// Create a new bump arena.
let bump = Bump::new();
// Create a vector of integers whose storage is backed by the bump arena. The
// vector cannot outlive its backing arena, and this property is enforced with
// Rust's lifetime rules.
let mut v = Vec::new_in(&bump);
// Push a bunch of integers onto `v`!
for i in 0..100 {
v.push(i);
}
}
最终,所有 std
集合类型都将通过分配器参数化,我们可以删除此 collections
模块并使用 std
版本。
有关 std
中不稳定、nightly-only 自定义分配器的支持,请参阅下面的 allocator_api
部分。
bumpalo::boxed::Box
当 "boxed"
cargo 功能启用时,在 boxed
模块中可得到 std::boxed::Box
的分支。此 Box
类型被修改为在其 bumpalo::Bump
区域内分配空间。
当 Box<T>
被丢弃时,将运行 T
的丢弃实现。 您可以使用此功能来绕过 Bump
不自行丢弃在其空间内分配的值的事实。
#[cfg(feature = "boxed")]
{
use bumpalo::{Bump, boxed::Box};
use std::sync::atomic::{AtomicUsize, Ordering};
static NUM_DROPPED: AtomicUsize = AtomicUsize::new(0);
struct CountDrops;
impl Drop for CountDrops {
fn drop(&mut self) {
NUM_DROPPED.fetch_add(1, Ordering::SeqCst);
}
}
// Create a new bump arena.
let bump = Bump::new();
// Create a `CountDrops` inside the bump arena.
let mut c = Box::new_in(CountDrops, &bump);
// No `CountDrops` have been dropped yet.
assert_eq!(NUM_DROPPED.load(Ordering::SeqCst), 0);
// Drop our `Box<CountDrops>`.
drop(c);
// Its `Drop` implementation was run, and so `NUM_DROPS` has been
// incremented.
assert_eq!(NUM_DROPPED.load(Ordering::SeqCst), 1);
}
Serde
添加 serde
功能标志将启用 Vecs 和boxed值的无缝序列化。
[dependencies]
bumpalo = { version = "3.9", features = ["collections", "boxed", "serde"] }
use bumpalo::{Bump, boxed::Box, collections::Vec};
// Create a new bump arena.
let bump = Bump::new();
// Create a `Box`
let box = Box::new_in("hello", &bump);
// Serialize with serde_json
assert_eq!(serde_json::to_string(&box).unwrap(), "\"hello\"");
// Create a `Vec`
let vec = Vec::new_in( &bump);
vec.push(1);
vec.push(2);
// Serialize with serde_json
assert_eq!(serde_json::to_string(&vec).unwrap(), "[1, 2]");
#![no_std]
支持
Bumpalo 默认是一个 no_std
crate。它只依赖于 alloc
和 core
crates。
std
支持
您可以选择启用 std
功能以启用某些集合的仅 std 特性实现。
std::io::Write
用于Vec<'bump, u8>
线程支持
Bump
是 !Sync
,这使得它在某些线程相关的场景下难以使用——例如在 rayon
中。
bumpalo-herd
包提供了用于此类场景的 Bump
分配器的池。
夜间Rust allocator_api
支持
不稳定、仅在夜间Rust中可用的 allocator_api
功能定义了一个 Allocator
特性,并公开了 std
类型使用的自定义分配器。Bumpalo 有一个匹配的 allocator_api
cargo 功能来启用实现 Allocator
并使用 Bump
与 std
集合。注意,由于 feature(allocator_api)
是不稳定的,并且仅在夜间Rust中,Bumpalo 的匹配 allocator_api
cargo 功能应被视为不稳定,并且不会遵循该软件包其余部分所遵循的 semver 规范。
首先,在您的 Cargo.toml
中启用 allocator_api
功能
[dependencies]
bumpalo = { version = "3", features = ["allocator_api"] }
接下来,在您的 src/lib.rs
或 src/main.rs
中启用 allocator_api
夜间Rust功能
#![feature(allocator_api)]
最后,使用 std
集合与 Bump
,这样它们的内部堆分配将在给定的bump竞技场内进行
use bumpalo::Bump;
// Create a new bump arena.
let bump = Bump::new();
// Create a `Vec` whose elements are allocated within the bump arena.
let mut v = Vec::new_in(&bump);
v.push(0);
v.push(1);
v.push(2);
在稳定Rust上使用 Allocator
API
您可以通过启用 allocator-api2
Cargo功能,bumpalo
将使用 allocator-api2
包在稳定Rust上实现不稳定夜间的 Allocator
API。这意味着 bumpalo::Bump
可以与任何泛型为 allocator_api2::Allocator
的集合一起使用。
最低支持的Rust版本(MSRV)
该软件包保证在稳定Rust 1.73 及以上版本上编译。它可能与较旧版本兼容,但这可能会在任何新的补丁版本中更改。
我们保留在次要版本中增加MSRV的权利,但我们将努力仅在故意并且有良好理由的情况下这样做。
依赖关系
~230KB