rusty_alloc
A pure-Rust remake of mimalloc — the v2.4.5 architecture (32 MiB segments, free-list-sharded pages, lock-free cross-thread frees), rebuilt from the design rather than transliterated from the C. No C anywhere in the product; the C mimalloc is a development-only differential oracle and is never a dependency.
Status: 0.7.0 — a 0.x release; the API is not frozen.
Upgrade from 0.3.x or earlier — mandatory. 0.4.0 fixed three platform-independent use-after-frees on the abandon → adopt → reuse path. Treat 0.3.2 and earlier as unsound on every target.
Tested on x86-64/aarch64 Linux, aarch64/x86-64 macOS and x86-64 Windows;
executed on wasm32-unknown-unknown (Node VM self-test, no emscripten).
What it is
- ~150 of mimalloc's ~157
mi_*entry points, semantics-for-semantics, gated against the C implementation as a differential oracle. - A double free is detected and aborted, on both the owner and cross-thread paths. Upstream mimalloc accepts it silently in release builds; handing the same block to two owners is the failure this project exists to prevent.
- Runs on WebAssembly via
memory.grow, with no C toolchain.
Performance (instruction counts, not seconds)
Measured deterministically via callgrind instructions retired, x86-64 Linux,
LD_PRELOAD:
| workload | vs mimalloc | vs glibc |
|---|---|---|
| lua | 0.98 | 0.83 |
| perl | 1.00 | 0.82 |
| sqlite | 1.00 | 0.99 |
The per-operation scan (small/med/big/large/huge, calloc, realloc, aligned, usable, batch and mixed working-set ops) measures at-or-below mimalloc on all 13 operations. Wall-clock time is deliberately not claimed: the measurement box cannot resolve it above its own noise floor, and instructions are not seconds.
Correctness on real software: jq, sqlite3, python3, git, xz, zstd, lua and perl produce byte-identical output under rusty_alloc, mimalloc and glibc; the full mimalloc-bench corpus (19 configurations, including the 8–16-thread storms) runs clean; Miri is clean over the whole target.
Usage
This crate is the allocator core. For the ergonomic Rust surface
(GlobalAlloc, first-class Heap, the Allocator trait), use
rusty_alloc-api.
Long-lived services should set purge_delay >= 0 — the configuration with
flat, measured RSS. The shipped default leaves purging opt-in.
Features
| feature | what |
|---|---|
debug_checks |
full invariant validation: list walks, span tiling, page canaries |
secure |
guard pages, encrypted free lists, guarded-object sampling (measured cost 4–7%) |
profile |
feature-gated path profiler |
Statistics counters follow upstream's MI_STAT rule: present in debug builds,
compiled out of release.
License
MIT. See LICENSE at the repository root.