Open-source project
fitzgen/bumpalo avatar
fitzgen/bumpalo

bumpalo: the Rust arena that frees everything by moving one pointer

A fast bump allocation arena for Rust

2,358 stars160 forksRustApache-2.0

At a glance

What is it?
A Rust crate that hands out memory from a chunk and never frees it individually, trading per-object deallocation for allocation speed. It pays off when you can name the phase of your program where everything dies at once, and costs you destructors when you cannot.
Who is it for?
bumpalo earns its place in a compiler pass, a parser, or a batch of nodes that all die at the same moment, and it earns it cheaply: version 3.21.0 in Cargo.toml, MIT OR Apache-2.0, a declared rust-version of 1.91.0, and a default feature set that is empty so the crate stays usable under no_std.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 11 days ago.
What is it written in?
Mainly Rust, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 25, 2026, and from our analysis. They are not legal advice.

From daily snapshots

Star history

  • fitzgen/bumpalo2,358 ★ · +11
Star history
Repository2026-10-072026-10-25
fitzgen/bumpalo2.3k2.4k

11 Stars in the last 18 days, measured from the daily GitHub snapshot. Compare with other projects

Editorial analysis

One capacity check and a pointer bump, nothing else

The allocator's hot path is short enough to state in one breath, which is the whole reason it is fast. You hold a chunk of memory and a pointer into it. Every allocation compares the requested size against the capacity left in the current chunk, then advances the pointer by that size. There is no free list, no size class lookup, no coalescing, and no per-object bookkeeping to keep consistent.

The cost shows up in the next sentence of the README: there is no general way to deallocate individual objects or reclaim the memory region for something that is no longer in use. Once the pointer has moved past an object, nothing inside the arena can move it back. When a chunk fills up, the implementation asks the global allocator for a new chunk and starts bumping into that one instead, and the older chunks stay owned by the arena until the arena itself goes away.

So the unit of memory management is the arena, not the value. That framing settles whether bumpalo fits your program before you write any code. Reach for it when allocations cluster in time, and be skeptical when a long-lived structure holds many small children you would like to release incrementally.

The README's opening example shows the intended shape. It allocates a small struct into a fresh arena and gets an ordinary exclusive mutable reference back:

Phase-oriented allocation, and the destructor it gives up

rust
use bumpalo::Bump;

struct Doggo {
    cuteness: u64,
    age: u8,
    scritches_required: bool,
}

// Create a new arena to bump allocate into.
let bump = Bump::new();

The README calls this pattern phase-oriented allocation and defines it as a group of objects that are all allocated during the same program phase, used, and then deallocated together as a group. Compilers, parsers, deserializers and query planners all have phases like that, which is why arena allocators keep turning up in that world.

The teardown is where the economics live. To free an entire arena you reset the bump pointer back to the start of the chunk, and that single store returns every byte to the arena's capacity. For a workload allocating hundreds of thousands of small nodes, the difference between a per-object free and one pointer write is not a percentage, it is a different order of work.

The catch arrives immediately. Resetting the pointer does not run Drop implementations for values that lived in the arena, and any type allocated with Bump::alloc and then let go of scope leaks whatever it owned. For plain data that is fine, and plain data is most of what a compiler puts in an arena. For a type holding a file handle, a lock, or a registration in some other table, it is not fine. That trade is deliberate, and the README spends a paragraph on it rather than burying it.

The boxed feature exists to buy Drop back

The crate does not simply hand you a leaky allocator and step away. With the boxed cargo feature enabled, a fork of std::boxed::Box is available in the boxed module, modified to allocate its space inside a Bump arena. A Box<T> runs T's Drop implementation when the wrapper is dropped, which is exactly the escape hatch from the paragraph above.

The README is careful about what you get back. The wrapper invokes the destructor but does not deallocate the backing memory, which is the right thing to want: you recover the destructor half of ownership without recovering free. The comparison it draws is to how std::boxed::Box behaves, with that one difference.

That makes the mental model slightly more precise than the usual arena description. Two drop paths exist, and they are not interchangeable. A value placed in the arena with alloc is reclaimed silently when the arena resets. A value placed in a bumpalo::boxed::Box gets its destructor called, and only the memory is left behind. If your type owns something outside the heap, you want the second path.

Arena-backed collections borrow the arena's lifetime

With the collections cargo feature enabled, forks of several standard library collection types become available in the collections module, modified so they allocate their space inside a Bump arena rather than through the global allocator. The constructor to remember is Vec::new_in(&bump), which is how such a collection acquires its backing storage.

The guarantee worth noting is enforced by the compiler rather than promised in prose. The README states that the vector cannot outlive its backing arena and that this property is enforced with Rust's lifetime rules. That is stronger than most allocator wrappers offer. An arena-backed collection used past the end of its arena is a borrow-check error at compile time, not a memory bug discovered later.

rust
    // 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);

The module is also explicitly temporary. The README says that eventually all std collection types will be parameterized by an allocator, that at that point this collections module can be removed, and that the std versions would be used instead. It links the tracking issue for that work. Reading bumpalo today means choosing between a stable feature that duplicates std types and an unstable feature that will eventually replace them.

Feature flags, the no_std default, and what the crate pulls in

Cargo.toml puts the crate at version 3.21.0 on edition 2021 with rust-version = "1.91.0", and the license field reads MIT OR Apache-2.0, which matches the LICENSE-APACHE and LICENSE-MIT files in the repository root. The categories name memory-management, rust-patterns and no-std, and documentation points at docs.rs.

The feature list is short and entirely additive. default is empty, and collections, boxed, allocator_api, std and serde are opt-in. That empty default matters more than it first appears: the README states that bumpalo is a no_std crate by default and depends only on the alloc and core crates. Enabling std buys exactly one thing worth naming, a std::io::Write implementation for Vec<'bump, u8>, which is what lets arena-allocated byte buffers go straight into an io::Write sink.

The optional dependencies line up with the features. allocator-api2 at version 0.2.8 and serde at 1.0.171 are both optional, and the serde feature is described as transparent serialization of Vecs, Strings and boxed values, so an arena-backed collection serializes without a wrapper type of your own.

toml
[dependencies]
bumpalo = { version = "3.18", features = ["collections", "boxed", "serde"] }

allocator_api is the forward path and the least settled one

The feature most likely to matter to you over time is allocator_api, and it is also the one the README hedges hardest. The unstable nightly-only Rust allocator_api feature defines an Allocator trait and exposes custom allocators for std types. Bumpalo has a matching cargo feature so that Bump can implement Allocator and be used with std collections. With it enabled, standard collections allocate inside a given arena.

Two caveats sit in the README and both carry weight. The crate depends on allocator-api2 rather than the nightly trait directly, so the stable-Rust path is a backport of the unstable trait rather than the trait itself. And stated more firmly, because feature(allocator_api) is unstable and nightly-only, bumpalo's matching cargo feature should be considered unstable and will not follow the semver conventions the rest of the crate does. That is the project describing its own compatibility promise, which is the kind of sentence worth reading twice before a dependency reaches a release branch.

So the decision is a real trade rather than a preference. On stable Rust, collections plus Vec::new_in is the route, at the cost of using the crate's forked types. On nightly, allocator_api removes the fork at the cost of an exemption from semver. The CHANGELOG.md in the repository root is where the history of that exemption would show up, since the GitHub releases list for this repository carries no entries.

Peak memory, and the workloads where an arena is the wrong shape

Two failure modes deserve bluntness. The first is the destructor problem: it stays invisible until the type you put in the arena turns out to own something outside the heap, and the arena offers no way to find out in advance.

The second is peak memory, and it follows directly from the design. Nothing is reclaimed individually, so an arena's high-water mark is the sum of everything allocated during the phase rather than the largest set still alive. For a pass that allocates a great deal and retains little, that is efficiency. For a pass that allocates one enormous temporary object and then runs for a long time afterwards, the arena holds that memory for the remainder of the phase, which is a worse trade than the fast allocation ever was.

The alternatives are concrete rather than abstract. If you want std collections in an arena on stable Rust, the collections feature with Vec::new_in(&bump) is what the crate provides today. If you can run nightly and want std types with a custom allocator, allocator_api is the forward path, with the semver caveat stated above. And if the real requirement is pooling with genuine reuse, that is a different category of allocator: the repository's own benchmark setup depends on blink-alloc pinned at version 0.4.0 alongside criterion 0.3.6, which is a fair hint about how the maintainers compare arena strategies against each other.

The maintenance picture is plain. The last push was on 2026-09-16 and the repository is not archived. The tree also carries a SECURITY.md, a valgrind.supp file for memory checking, and separate tests/try_alloc.rs and benches/benches.rs entries in Cargo.toml, so the fallback path when a chunk cannot satisfy an allocation is something the project tests explicitly rather than an afterthought.

Editorial conclusion

bumpalo earns its place in a compiler pass, a parser, or a batch of nodes that all die at the same moment, and it earns it cheaply: version 3.21.0 in Cargo.toml, MIT OR Apache-2.0, a declared rust-version of 1.91.0, and a default feature set that is empty so the crate stays usable under no_std. What it will not do is free a single value early, run Drop for anything you placed with Bump::alloc, or promise semver stability for its own allocator_api feature, which the README explicitly exempts from it. Start from the docs.rs page rather than the README, since the README's last example stops before its first statement, and decide between the collections feature and allocator_api before you commit to either.

Frequently asked questions

What is a bump allocator?

It is an allocator that keeps a chunk of memory and a pointer into it, checking remaining capacity on each allocation and then advancing the pointer by the object's size. Because the pointer never moves backwards, individual objects cannot be freed, so all memory in the arena is reclaimed at once by resetting the pointer. Bumpalo is a Rust implementation of that idea.

What are the different types of memory allocators in programs?

The families the bumpalo README contrasts itself with are the general-purpose allocators, where each allocation carries its own bookkeeping and can be freed individually, and the arena or pool style, where allocation is cheap and reclamation happens in bulk. Bumpalo sits in the second group, which is why its collections are tied to an arena's lifetime rather than being free-standing types.

Does bumpalo run destructors when the arena is dropped?

Not for values allocated with Bump::alloc, because resetting the pointer reclaims memory without invoking Drop implementations. The boxed cargo feature exists for that case: bumpalo::boxed::Box allocates inside the arena but runs T's Drop implementation when the wrapper itself is dropped, without deallocating the backing memory.

Official sources

  1. fitzgen/bumpalo on GitHub
  2. Issues
  3. License: Apache-2.0
  4. Project website
  5. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/fitzgen-bumpalo.svg)](https://hysenlabs.com/projects/fitzgen-bumpalo)

Star history chart for your README

markdown
[![Star history](https://hysenlabs.com/chart/fitzgen-bumpalo.svg)](https://hysenlabs.com/projects/fitzgen-bumpalo)

Was this useful?