tree: 3de9c2c33d926b63e73ca19689208d4e41f0a358 [search]
  1. src/
  2. sys/
  3. tests/
  4. .gitignore
  5. build.rs
  6. Cargo.toml
  7. README.md
contrib/rust/README.md

mimalloc for Rust

Rust bindings for mimalloc, built directly from the mimalloc sources in this repository. As usual for Rust FFI bindings, these are split into two crates:

  • mimalloc-sys (in sys/): builds and links the C library and has the raw C API.
  • mimalloc: the global allocator, heaps, and safe helpers (with the raw API re-exported as mimalloc::sys).
use mimalloc::MiMalloc;

#[global_allocator]
static GLOBAL: MiMalloc = MiMalloc;
  • MiMalloc: the global allocator (with fast paths for small and sized allocations).
  • Heap: first-class heaps that can be shared between threads; dropping a heap keeps its live blocks valid (Heap::destroy frees them all at once).
  • Arena: reserve memory for heaps that only allocate in it (see Arenas).
  • sys: the raw C API (mimalloc.h).
  • Both MiMalloc and &Heap implement core::alloc::Allocator on Rust 1.100+ (or on an older nightly with the nightly feature).
  • Helpers such as collect, option_set, stats_print and stats_json.

Arenas

An arena is a large area of memory that heaps allocate from. A heap created with Heap::new_in_arena only allocates in its arena, and returns null when the arena is full.

use mimalloc::{Arena, Heap, ReserveOptions};

let options = ReserveOptions { exclusive: true, ..ReserveOptions::default() };
let arena = Arena::reserve_from_os(64 << 20, options).unwrap();
let heap = Heap::new_in_arena(arena);
  • Arena::reserve_from_os reserves fresh OS memory; Arena::from_static_memory uses memory that lives forever (such as a leaked Box); Arena::from_external_memory (unsafe) uses any other memory. They return None if the arena cannot be created.
  • An exclusive arena keeps all other heaps out; otherwise any heap can use it as well.
  • Arenas cannot be removed, so they live until the process exits.
  • Arenas need at least Arena::min_size() bytes (32 MiB on 64-bit), and their start is aligned to Arena::min_alignment() (256 MiB on 64-bit, or 64 KiB with the secure feature), so memory at an unaligned address needs max(min_size, min_alignment) + min_alignment bytes.

Features

FeatureDescription
secureSecurity mitigations (guard pages, randomization, encoded free lists)
overrideAlso override malloc, free, etc. in the final binary
debugBuild mimalloc with assertions and internal checks
debug_in_debugAs debug, but only when debug_assertions are on
local_dynamic_tlsUse the local-dynamic TLS model (for dynamically loaded libraries)
win_direct_tlsUse direct TLS slots on Windows
no_thpDisable transparent huge pages by default on Linux
opt_archArchitecture specific optimizations (as -DMI_OPT_ARCH=ON)
mteMemory tagging; requires MTE support at runtime (aarch64 Linux, Android, and Apple only (where macOS also needs the MTE entitlement); as -DMI_MTE=ON)
pacSign internal pointers with pointer authentication; requires PAC support at runtime (aarch64 Linux, Android, and Apple only; as -DMI_PAC=ON)
nightlyAllocator support on nightly compilers before Rust 1.100 (mimalloc only)

All features except nightly are build options of the C library in mimalloc-sys (and are forwarded by mimalloc). Feature mte does not a separate secure (but encompasses it). The combination mte and pac offers strong hardware supported security mitigation.

Architecture optimizations are also enabled automatically if the Rust target features already imply them (e.g. -C target-cpu=native).

Features can be enabled per target, e.g. to only override malloc on Linux:

[target.'cfg(target_os = "linux")'.dependencies]
mimalloc = { path = "path/to/mimalloc/contrib/rust", features = ["override"] }

Other build options can be passed as C defines in the MIMALLOC_DEFINES environment variable (separated by spaces or commas); these take precedence over the defines set by features. For example: MIMALLOC_DEFINES="MI_DEBUG=3 MI_SKIP_COLLECT_ON_EXIT=1" cargo build.

Using the crate

The C sources are found by mimalloc-sys in the following order:

  1. The MIMALLOC_SRC_DIR environment variable.
  2. A vendored mimalloc/ directory next to sys/Cargo.toml (with include/, src/, and LICENSE).
  3. The enclosing repository (../../.. from sys/).

Within this repository, use a path or git dependency:

[dependencies]
mimalloc = { path = ".../mimalloc/contrib/rust" }

To publish crates based on these, copy contrib/rust, vendor the sources into sys/mimalloc/ (cp -r ../../include ../../src ../../LICENSE sys/mimalloc/), and rename both packages (the names mimalloc and mimalloc-sys are already taken on crates.io). The mimalloc crate depends on the exact version of mimalloc-sys as its fast paths depend on internal entry points such as mi_wmalloc_small and MI_SMALL_SIZE_MAX.

Performance tips

  • Enable LTO so that allocations in other crates (and std) are inlined with a statically known size and alignment (instead of going through the __rust_alloc shim):
    [profile.release]
    lto = "thin"
    
  • Optimize mimalloc in debug builds too (the C library is compiled as part of mimalloc-sys):
    [profile.dev.package.mimalloc-sys]
    opt-level = 3
    
  • Cross-language LTO can inline the allocation fast paths into Rust code: build with clang (matching the LLVM version of rustc) using CC=clang CFLAGS=-flto=thin and RUSTFLAGS=-Clinker-plugin-lto (see the rustc linker-plugin-lto documentation).

Testing

cargo test --workspace
cargo test --release --features secure
cargo test --features debug,override
cargo +nightly test --features nightly

The tests also run as test-rust with ctest in a CMake build (if cargo is found), using features that match the CMake configuration.