Skip to content

Repository files navigation

crates.io docs.rs CI license remade with rust

rusty_alloc

A ground-up, pure-Rust general-purpose allocator — the mimalloc v2.4.5 architecture rebuilt from the design rather than transliterated from the C. No C in the dependency tree, permissive licence, and a safety property upstream does not offer.

⚡ The headline

  • Parity with mimalloc on instructions retired, and ~16% fewer than glibc, on real programs under LD_PRELOAD.
  • A double free aborts instead of corrupting. Upstream mimalloc accepts it silently in release builds; we detect it on both the local and the cross-thread path and abort, for a measured ~0.4%.
  • ~150 of mimalloc's ~157 mi_* entry points, gated against the C implementation as a differential oracle on every change.
  • Runs on WebAssembly with no C toolchain and no emscripten.

Status: 0.4.0 — a 0.x release. The API is not frozen, and parts of the performance evidence are still missing. 0.4.0 fixed three platform-independent use-after-frees, so 0.3.2 and earlier should be treated as unsound on every target — upgrade rather than pin. See What is and isn't measured — we count instructions, not seconds, and make no speed claim.

Performance (this machine, deterministic)

Instructions retired under callgrind, x86-64 Linux, real programs via LD_PRELOAD. Repeats to 4–6 significant figures.

workload vs mimalloc vs glibc
lua 0.99 0.84
perl 1.01 0.83
sqlite 1.00 1.00

Method. bench/icount-arms.sh. Instruction counts, not wall-clock — chosen deliberately, because this machine's timing noise floor is wider than the effect (see below). Counts are immune to scheduler, thermal and load artifacts; they are also not a measure of time.

What is and isn't measured

Wall-clock: measured, and it cannot resolve the difference. bench/wallclock.sh runs pinned, ABBA-interleaved, N=31, microsecond timer, with a null arm — the same allocator compared against itself:

arm median ratio
null (rusty_alloc vs ITSELF) 1.0117
perl, rusty_alloc vs mimalloc 1.0009
sqlite, rusty_alloc vs mimalloc 1.0091

The null arm is 1.17% — wider than either effect. The honest reading is "at parity, below measurement resolution". Reproduce on a quiet box with N=31 bash bench/wallclock.sh.

Scope that claim to these workloads. A 0.4.0 re-run against the same mimalloc oracle, but on a pure allocation-CHURN microbenchmark (all arms LD_PRELOADed into one neutral C binary, instructions retired), reads 1.1342 × mimalloc — 13.4% behind — while still being 0.67 × glibc. Real programs dilute allocator cost among everything else they do; a loop that does almost nothing but malloc/free does not. "At parity" is measured on lua/perl/sqlite and should not be read as a general property.

Not measured, and therefore not claimed:

  • The full mimalloc-bench corpus. Three workloads, not the suite — the project's own v1 gate (geomean within 10%, no bench >25% behind, RSS within 15%) is not yet demonstrated.
  • RSS. No systematic footprint sweep. Three things were measured in 0.4.0 on aarch64-apple-darwin, and one of them is a caveat, not a win:
    • The decommit primitive now returns 100.1% of touched pages to the OS (it returned 6.4% before the fix — MADV_DONTNEED is advisory-only for anonymous memory on Darwin).
    • With purging enabled (purge_delay = 0), a 6-minute thread-churn soak held RSS flat at 9.4 MiB, slope −0.02 MiB/min.
    • With the shipped default (purge_delay = -1, purging OPT-IN), a 25-minute soak against a bounded live set (~175 MiB mean) sat at ~650 MiB RSS and drifted +1.45 ± 0.70 MiB/min over the full run. The drift decelerates (first half +2.42, second half +1.19 ± 1.87 — no longer distinguishable from zero) and RSS does not track the live set (corr = +0.03), which is consistent with retention approaching a plateau rather than an unbounded leak — but 25 minutes cannot tell those two apart, and this is not claimed to be settled.
  • Long-running behaviour beyond ~25 minutes. Multi-day fragmentation is unknown. Long-lived services should set purge_delay >= 0 rather than rely on the opt-in default.

aarch64 is now executed (0.4.0). It was not, through 0.3.2, and that first execution cost seven defects — two of them memory-safety class, including a thread_id() that read the wrong system register on Darwin and let distinct threads collide onto one ownership id. See the 2026-08-08 entries in docs/LEDGER.md. Three of the seven were platform-independent use-after-frees that x86-64 had been surviving by luck, so 0.3.2 and earlier should be treated as unsound on every target, not merely on aarch64.

There is no "faster than mimalloc" claim anywhere in this repository, because the evidence for one does not exist yet.

What is this?

A reimplementation, not a binding. There are excellent mimalloc bindings for Rust; this is not one of them. Every line of the allocator is Rust, the C mimalloc in this repository is a development-only differential oracle, and it is never a dependency and never published.

unsafe is confined to the places an allocator genuinely needs it — the OS primitive layer, page and segment metadata, and the lock-free cross-thread protocol — with a stated invariant on every block, unsafe_op_in_unsafe_fn denied and undocumented_unsafe_blocks denied workspace-wide.

The Remade With Rust ecosystem

project what
rusty_alloc this — pure-Rust general-purpose allocator
rusty_h264 pure-Rust H.264 encoder and decoder
Mata Network the parent organisation

Features

Allocator core — 32 MiB segments sliced into 64 KiB spans, free-list-sharded pages, the loom-verified four-state cross-thread free protocol, thread abandonment and adoption, first-class heaps, arenas, huge allocations, aligned allocation with interior-pointer recovery, and the full realloc family.

Safety — double-free detection on both the owner and cross-thread paths; Miri-clean; a 640-thread churn probe; debug_checks for full invariant validation; secure for guard pages, encrypted free lists and guarded-object sampling.

Portability — x86-64 and aarch64, Linux and Windows, plus wasm32-unknown-unknown via memory.grow.

Install

[dependencies]
rusty_alloc-api = "0.3"
crate docs what
rusty_alloc docs.rs allocator core
rusty_alloc-api docs.rs safe Rust surface — start here

The FFI, LD_PRELOAD override, bench and wasm crates are publish = false: harnesses, fixtures and native artifacts, not libraries.

Quick start

use rusty_alloc_api::RustyAlloc;

#[global_allocator]
static ALLOC: RustyAlloc = RustyAlloc;

fn main() {
    let v: Vec<u64> = (0..1_000).collect();
    println!("{}", v.iter().sum::<u64>());
}

Architecture

crates/rusty_alloc            allocator core       (published)
crates/rusty_alloc_api        safe Rust surface    (published)
crates/rusty_alloc_ffi        mi_*-compatible C ABI
crates/rusty_alloc_override   malloc/free interposition cdylib
crates/rusty_alloc_bench      Tier-B harness + trace record/replay
crates/rusty_alloc_wasm       wasm self-test fixture
oracle/mimalloc               C mimalloc @ v2.4.5 — dev-only oracle
corpus/mimalloc-bench         the 1:1 benchmark corpus
docs/LEDGER.md                one entry per milestone: numbers, method, reverts
docs/plans/rusty_alloc_v1.md  plan of record — API inventory, gate ladder

Benchmarking

git submodule update --init oracle/mimalloc corpus/mimalloc-bench
bash oracle/build.sh                 # build the C oracle arms
bash bench/icount-arms.sh            # deterministic instruction A/B
N=31 bash bench/wallclock.sh         # wall-clock, with a null arm
bash bench/opscan.sh                 # per-operation scan vs mimalloc

Gates

Every change runs Windows + Linux suites (all features), clippy -D warnings, Miri, a 640-thread churn probe, a wasm VM self-test, and a deterministic instruction A/B against the C oracle. The 0.4.0 release gates additionally ran the full workspace green on aarch64-apple-darwin, x86_64-apple-darwin, aarch64-unknown-linux-gnu and x86_64-unknown-linux-gnu, with a 100/100 stress_mt release soak (0.3.2 managed 0/20). docs/LEDGER.md records what each milestone measured — including the changes reverted for being flat or slower, which is most of them.

Platform support

target status
x86-64 Linux tested; the LD_PRELOAD and measurement path
x86-64 Windows tested on 0.4.0 — full suite green; 640-thread create/teardown churn clean; exercised as #[global_allocator] by six shipping codec projects (see below)
aarch64 macOS (Apple Silicon, 16 KiB pages) tested — full suite, 100/100 stress soak, #[global_allocator] app
aarch64 Linux tested — full suite, 40/40 stress soak
wasm32-unknown-unknown executedbench/wasm-selftest.mjs passes in a Node VM; not exercised in a browser

The x86-64 Windows evidence (0.4.0)

The 0.4.0 gates ran on Darwin and Linux; Windows was validated separately, downstream, on the projects that consume it as #[global_allocator]. Every result below is byte-identical output before and after the allocator swap, not merely "it ran":

project gate
rusty_av2d 45/45 AV2 conformance clips byte-identical vs AOM's avmdec, + 111 tests
rusty_av1d 12/12 test-vector md5s unchanged; identical at 1/2/4/8 threads; 10/10 clean process exits
rusty_av1e encoder bitstream FNV c54bb3b1b3ccbad1 unchanged
remade_ffmpeg_rs workspace suites + a 30,000-input fuzz across 16 decoders, zero panics
rusty-opus / rusty_png / rusty_jpeg 48 / 61 / 48 tests

Plus a targeted probe for the one 0.4.0 change that reaches Windows — the subproc tag moving off Rust thread_local! storage, because destruction order against a platform TLS destructor (FlsAlloc here) is unspecified: 16 threads × 40 rounds of mixed-size-class churn, 640 create/teardown cycles, clean.

Note for anyone running the suite: use a debug build. The allocation counters behind alloc::stats() are #[cfg(debug_assertions)], so churn_sweep_randomized — which asserts on them — fails under cargo test --release on every platform, not just Windows.

License

MIT — see LICENSE. No GPL or LGPL anywhere in the tree. The vendored oracle and benchmark corpus are development-only, keep their own licences, and never ship.

About Mata Network

rusty_alloc is part of the remade-with-rust portfolio from Mata Network: foundational software rebuilt in Rust, memory-safe by construction, measured rather than asserted.

About

rusty_alloc is a pure-Rust, memory safe alternative to mimalloc. Cross platform combability across x86-64 linux and windows, aarch64, wasm

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages