Rallocator Logo # Rallocator [![crate.io](https://img.shields.io/crates/v/rallocator.svg)](https://crates.io/crates/rallocator) [![docs.rs](https://docs.rs/rallocator/badge.svg)](https://docs.rs/rallocator) [![MSRV](https://img.shields.io/crates/msrv/rallocator)](https://crates.io/crates/rallocator) [![CI](https://github.com/microsoft/oxidizer/actions/workflows/main.yml/badge.svg?event=push)](https://github.com/microsoft/oxidizer/actions/workflows/main.yml) [![Coverage](https://codecov.io/gh/microsoft/oxidizer/graph/badge.svg?token=FCUG0EL5TI)](https://codecov.io/gh/microsoft/oxidizer) [![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/microsoft/oxidizer/blob/main/LICENSE) This crate was developed as part of the Oxidizer project
A pure-Rust, high-performance allocator with scoped heaps and telemetry. ## Supported platforms `rallocator` currently supports Windows and Linux. Other operating systems are outside the crate’s public support contract and intentionally fail to compile. Miri uses an internal test backend and is not a production support target. ## Usage ### General use Install the standard configuration as the process-global allocator: ```rust rallocator::rallocator!(); ``` The macro declares the required `#[global_allocator]` static and contains the unsafe call to [`Rallocator::new`][__link0], whose process-wide same-configuration invariant it establishes by construction. Ordinary allocations then use each thread’s implicit general heap. To group related allocations, use an [`allocation_hints`][__link1] prospective heap. These handles publish only a thread-local request. Rallocator lazily realizes the request and retains a bounded per-thread cache for later reattachment: ```rust use allocation_hints::heaps::{Heap, bump}; use allocation_hints::with_hint; rallocator::rallocator!(); let heap = Heap::bump(bump::Options::new()); let values = with_hint(&heap, || vec![1, 2, 3]); assert_eq!(values.len(), 3); ``` If another global allocator is installed, the same code remains valid and the hint may be ignored. ### Telemetry Telemetry is opt-in at compile time through [`rallocator!`][__link2]: ```rust use seismograph::recorder::{Configuration, RecordingPolicy}; rallocator::rallocator!(); fn main() -> Result<(), Box> { seismograph::recorder(Configuration { allocations: RecordingPolicy::all(true), ..Default::default() }); let mut values = vec![1, 2, 3]; values[0] += 1; std::hint::black_box(&values); drop(values); seismograph::recorder(Configuration::default()); seismograph::snapshot(seismograph::snapshot::SnapshotOptions::default()) .expect("telemetry snapshot capture succeeds") .write_file("snapshot.seismograph")?; Ok(()) } ``` Convert the snapshot to HTML with `seismograph snapshot html snapshot.seismograph`. Process-wide byte and operation counters remain active for the process lifetime. Threads publish these counters in batches of 256 operations; snapshots flush the capturing thread, while other active threads can lag by at most one batch. Per-size histograms, allocation events, and backtraces require Seismograph recording, which can be enabled only around the interval of interest to limit its overhead. The default `caller-symbolization` feature resolves captured instruction pointers through the optional `backtrace` dependency. Disabling default features retains caller tracking and raw addresses without in-process symbol resolution. ## Design guide Use the implicit thread-local general heap for ordinary allocations. Introduce prospective general heaps when you want locality boundaries without changing the mixed-size allocation model. Use bump heaps for phase-bounded work where individual frees are rare and bulk reclamation matters more than per-allocation reuse. Use [`allocation_hints::heaps::thread_heap`][__link3] when another thread should allocate into the current thread’s allocator-preferred heap. ## Implementation guide 1. Install and configure [`rallocator!`][__link4] exactly once as the process-global allocator. 1. Route special-purpose allocations with [`allocation_hints::with_hint`][__link5] and [`allocation_hints::heaps::Heap`][__link6]. 1. Enable Seismograph recording only when you need allocation events and backtraces; lifetime aggregate counters remain active. Invalid tunables fail early when [`Rallocator::new`][__link7] is instantiated: the size-class layout must be well-formed and the partial-slab scan limit must be non-zero. ## Internals Rallocator is organized as a hierarchy: * An internal allocation domain owns one or more 1 GiB virtual-memory **regions**, divided into 64 KiB **slices**. * A domain can serve multiple allocator-native heap realizations. Each heap keeps its own allocation state while drawing backing memory from its domain. * General heaps use slices for **locality segments** containing 32 KiB **slabs**, and for **medium spans** covering one or more slices. Bump heaps use slices as **bump chunks**. * Slabs contain same-sized **blocks**, which are the allocation slots returned for small requests. Large or highly aligned requests bypass this hierarchy and use direct operating-system mappings.
Allocator memory layout Domain-owned physical backing Process region: 1 GiB 64 KiB slice 64 KiB slice 64 KiB slice 64 KiB slice A bitmap records which slices are owned. Locality segment Consecutive slices owned by one general heap 32 KiB slab 32 KiB slab Medium span One or more consecutive slices slice 1 slice 2 Bump chunk One 64 KiB slice 32 KiB segment 32 KiB segment Direct mapping One large or highly aligned allocation. Managed independently by the operating system. Additional region Created when existing regions cannot provide a large enough free run. Uses the same layout. A slab contains blocks from one size class header block block block block block ... Example: every block in this slab is the selected 64-byte size class. Not to scale
Each thread has an implicit general heap. [`allocation_hints::with_hint`][__link8] can temporarily route allocations to a prospective general, bump, or thread-target heap; leaving the scope restores the previous request. This keeps the common allocation path thread-local while allowing runtimes and data structures to choose allocation topology deliberately. General heaps route requests by size and alignment: |Category|Size|Maximum alignment|Backing| |--------|----|-----------------|-------| |**Small**|Up to 16 KiB|4 KiB|One block in a 32 KiB slab| |**Medium**|Up to 1 GiB, when no small class fits|64 KiB|One or more 64 KiB slices| |**Large/direct**|Above 1 GiB, or alignment above 64 KiB|Operating-system limit|Dedicated mapping| Small frees normally return to the owning heap’s caches; cross-thread frees are queued for that owner. Medium spans are cached or returned to domain free lists, while direct mappings go back to the operating system. Detached prospective realizations remain in a bounded per-thread cache; eviction releases empty backing while preserving metadata needed by escaped allocations.
This crate was developed as part of The Oxidizer Project. Browse this crate's source code. [__cargo_doc2readme_dependencies_info]: ggGmYW0CYXZlMC43LjNhdIQb11VxC_uAPOQbtUn4Wx2-BfAbid3Nt1Y27Pobprn8Z6FjFy9hYvRhcoQbypoMx1WbAVobE3PgdRcrEt8bP9EGMsbHO_QbJf2ng-VTcMRhZIKCcGFsbG9jYXRpb25faGludHNlMC4xLjCCanJhbGxvY2F0b3JlMC4xLjA [__link0]: https://docs.rs/rallocator/0.1.0/rallocator/?search=Rallocator::new [__link1]: https://crates.io/crates/allocation_hints/0.1.0 [__link2]: https://docs.rs/rallocator/0.1.0/rallocator/macro.rallocator.html [__link3]: https://docs.rs/allocation_hints/0.1.0/allocation_hints/?search=heaps::thread_heap [__link4]: https://docs.rs/rallocator/0.1.0/rallocator/macro.rallocator.html [__link5]: https://docs.rs/allocation_hints/0.1.0/allocation_hints/?search=with_hint [__link6]: https://docs.rs/allocation_hints/0.1.0/allocation_hints/?search=heaps::Heap [__link7]: https://docs.rs/rallocator/0.1.0/rallocator/?search=Rallocator::new [__link8]: https://docs.rs/allocation_hints/0.1.0/allocation_hints/?search=with_hint