Lock-free arena allocator that produces bytes::Bytes via zero-copy freeze.
Write into a Buffer, freeze it into Bytes, and let the arena reclaim the backing memory when the last reference drops. The common path avoids a copy on freeze and avoids a fresh heap allocation per buffer.
use NonZeroUsize;
use FixedArena;
use BufMut;
let arena = builder.build?;
let mut buf = arena.allocate?;
buf.put_slice;
let _bytes = buf.freeze;
# Ok::
Allocator modes
FixedArena uses uniform slots. Allocation is a single bitmap claim. Use it when buffer sizes are predictable.
BuddyArena uses power-of-two blocks from one contiguous region. Requests are rounded up, larger blocks split on demand, and free blocks coalesce on release. Use it when sizes vary.
use NonZeroUsize;
use BuddyArena;
use BufMut;
let arena = builder.build?;
let mut buf = arena.allocate?;
buf.put_slice;
let _bytes = buf.freeze;
# Ok::
Auto-spill
By default, writing past buffer capacity panics. With auto_spill(), the buffer copies its current contents to heap-backed storage, frees the arena allocation immediately, and continues writing on the heap. freeze() still returns Bytes.
# use NonZeroUsize;
# use FixedArena;
# use BufMut;
let arena = builder.auto_spill.build?;
let mut buf = arena.allocate?;
buf.put_slice;
assert!;
let _bytes = buf.freeze;
# Ok::
Async allocation
With the async-alloc feature, both arena types support allocate_async(). The task waits until capacity is available and then retries against the live bitmap state.
[]
= { = "0.5", = ["async-alloc"] }
let arena = new;
let buf = arena.allocate_async.await;
Metrics
Use metrics() on FixedArena and BuddyArena to snapshot allocator state. Fixed reports allocation, failure, spill, and live-capacity counters. Buddy adds split, coalesce, and largest-free-block data.
In load tests, watch spill_count and largest_free_block over time to catch pressure and fragmentation early.
Examples
If you're new to the crate, run fixed_buffer first, then buddy_buffer for variable-size behavior.
| Example | What it shows |
|---|---|
fixed_buffer |
Allocate, write, freeze, and send across threads |
buddy_buffer |
Variable-size allocations with split and coalesce |
spill_buffer |
Auto-spill to heap when a buffer outgrows slot capacity |
async_alloc |
Wait for capacity with allocate_async() |
Benchmarks
Benchmark summary tables and local Criterion HTML report links are in
docs/benchmarks.md.
That page now includes both the Apple M4 Max baseline and a real-hardware
k8s run summary (normal + extreme modes).
Run benchmarks with:
bench:extreme enables an additional high-thread contention point (40 threads by default).
Override via ARENA_BENCH_EXTREME_THREADS=<n>.
Deployment guides
- NUMA-aware deployment pattern: per-node arenas, thread pinning, and bounded cross-node fallback.
Status
Pre-1.0. The crate is usable now, but the API may still move before it settles.
Contributing
See CONTRIBUTING.md for development workflow and PR expectations.
License
MIT