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

Download history 1100575/week @ 2024-04-29 1136271/week @ 2024-05-06 1194285/week @ 2024-05-13 1181852/week @ 2024-05-20 1162602/week @ 2024-05-27 1299208/week @ 2024-06-03 1278778/week @ 2024-06-10 1283669/week @ 2024-06-17 1317263/week @ 2024-06-24 1197722/week @ 2024-07-01 1318279/week @ 2024-07-08 1337374/week @ 2024-07-15 1386559/week @ 2024-07-22 1355905/week @ 2024-07-29 1328335/week @ 2024-08-05 1334757/week @ 2024-08-12

每月下载量5,477,274
34,126个crates(直接使用153个)中使用

MIT/Apache

335KB
3.5K SLoC

bumpalo

bumpalo是一个为Rust设计的快速bump分配竞技场。

Build Status

bump分配

bump分配是一种快速但有限的分配方法。我们有一块内存,并在其中维护一个指针。每当我们要分配一个对象时,我们会快速检查我们是否有足够的容量来分配该对象,然后根据对象的大小更新指针。**就这样!**

bump分配的缺点是没有一种通用的方法来处理单个对象的释放或回收不再使用的对象的内存区域。

这些权衡使bump分配非常适合**面向阶段**的分配。也就是说,一组将在同一程序阶段分配、使用然后可以作为一个组一起释放的对象。

大规模释放,但没有Drop

要一次性释放竞技场中的所有对象,我们可以简单地将bump指针重置回竞技场内存块的起始位置。这使得大规模释放**极其**快速,但不会调用分配对象的Drop实现。

然而: 可以使用 bumpalo::boxed::Box<T> 来包裹在 Bump 区域分配的 T 值,并在 Box<T> 包装器超出作用域时调用 TDrop 实现方式。这与 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。它只依赖于 alloccore 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 并使用 Bumpstd 集合。注意,由于 feature(allocator_api) 是不稳定的,并且仅在夜间Rust中,Bumpalo 的匹配 allocator_api cargo 功能应被视为不稳定,并且不会遵循该软件包其余部分所遵循的 semver 规范。

首先,在您的 Cargo.toml 中启用 allocator_api 功能

[dependencies]
bumpalo = { version = "3", features = ["allocator_api"] }

接下来,在您的 src/lib.rssrc/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