Skip to content

Releases: amsokol/mimalloc

v3.6.0

Choose a tag to compare

@amsokol amsokol released this 25 Oct 10:05
v3.6.0
05014c9

Updates to mimalloc v3.6.0 (upstream release of 2026-10-23, 223 commits after v3.5.3) and adapts mimalloc::Option to it.

[dependencies]
mimalloc = { git = "https://github.com/amsokol/mimalloc", tag = "v3.6.0" }

Before you upgrade: what can affect your program

  1. Breaking change in this crate: three mimalloc::Option variants were renamed, following upstream. Update the names if you use them:

    v3.5.3+1 v3.6.0 MIMALLOC_<NAME>
    Option::GuardedPrecise Option::UnsafeGuardedPrecise unsafe_guarded_precise
    Option::MinimalPurgeSize Option::ArenaPurgeMinSize arena_purge_min_size
    Option::CollectMergesStats Option::StatsMergeOnCollect stats_merge_on_collect

    Option::name() returns the new names. Of the old environment variables, only MIMALLOC_MINIMAL_PURGE_SIZE is still accepted (mimalloc keeps it as a legacy name); MIMALLOC_GUARDED_PRECISE and MIMALLOC_COLLECT_MERGES_STATS are silently ignored now, so rename them in your deployment. Option is #[non_exhaustive], and Option::ALL grew from 39 to 45 entries.

  2. Cross-thread page reclaim is now on by default (page_reclaim_on_free: 0 → 1). A thread that frees a block into an abandoned page can now take that page over, even when the page came from another thread. This is upstream's change to improve reuse and speed in multi-threaded programs; it can also change how much memory a program with many short-lived or pooled threads holds.

    • Since 3.6.0 the option is only a default for new heaps: each heap copies it when it is created. The heap behind the Rust global allocator is created before main, so Option::PageReclaimOnFree.set(..) from main does not change it. To get the 3.5 behaviour, start the process with MIMALLOC_PAGE_RECLAIM_ON_FREE=0.
  3. Large freed ranges are now returned to the OS immediately. A freed range of at least arena_purge_immediate_size (new option, 32 MiB by default, in KiB) is purged as it is freed, whatever purge_delay × arena_purge_mult says. A program that frees blocks of 32 MiB or more will see its RSS drop at once instead of after about 4 s, and may pay more page faults when it allocates such blocks again. A negative purge_delay still never purges. Option::ArenaPurgeImmediateSize.set(..) works from main (read on every free). collect(force) is unchanged.

  4. Memory layout of small blocks changed. Upstream now gives blocks a per-page, hashed cache offset for the first block, to spread small allocations over the CPU cache sets (upstream issue #1121), and moves 64 KiB blocks into large pages. The goal is fewer cache conflicts; the side effect is that the usable layout and the RSS of a program can differ somewhat from 3.5.x. Measure with process_info().current_rss if memory matters to you.

  5. Transparent huge pages (Linux). Upstream reworked how the huge page size is detected (it now reads hpage_pmd_size). If the kernel's huge page size is over 8 MiB (for example arm64 with 64 KiB pages), mimalloc now treats the system as having no THP and marks its mappings MADV_NOHUGEPAGE. On the usual 2 MiB x86-64 setup nothing changes: allow_thp still defaults to 2, no_thp still builds with MI_DEFAULT_ALLOW_THP=0, and MIMALLOC_ALLOW_THP=0 still overrides it.

  6. A heap profiler is now compiled in and always available. Upstream built a profiler into mimalloc (MI_PROFILE, on by default). Upstream says it adds overhead only once it is activated with MIMALLOC_PROFILE=<basename>, which writes pprof snapshots (I did not measure the cost of having it compiled in). Its settings are the new Option::Profile* variants (MIMALLOC_PROFILE_ALLOC_INTERVAL, _INUSE_INTERVAL, _TIME_INTERVAL, _SAMPLE_RATE); the profiler reads them once at process start, so set them with environment variables, not with Option::set from main. Upstream also keeps detailed statistics per size bin always on. Limitation of this crate: upstream's CMake build detects execinfo.h/libunwind and defines MI_HAS_EXECINFOH; this crate's build.rs does not, so on Unix the profiler records samples without call stacks (its backtrace function is a stub returning 0 frames). On Windows it uses CaptureStackBackTrace. I checked on Linux that MIMALLOC_PROFILE writes snapshot files; they contain no stacks.

Changes in this crate

  • c_src/mimalloc is v3.6.0. build.rs needed no change: src/static.c still includes the sources, which upstream moved into src/alloc, arena, heap, prim, profile and util (so options.c is now src/util/options.c).

  • mimalloc::Option follows mi_option_t of 3.6.0: the three renames above and six new variants:

    Variant MIMALLOC_<NAME> Default Notes
    ProfileAllocInterval profile_alloc_interval 1 GiB bytes allocated between profiler snapshots; 0 disables
    ProfileInuseInterval profile_inuse_interval 0 (off) snapshot when in-use bytes grew by this much
    ProfileTimeInterval profile_time_interval 0 (off) seconds between snapshots
    ProfileSampleRate profile_sample_rate 512 KiB profiler sampling rate in bytes
    StatsMergeThreshold stats_merge_threshold 512 KiB merge thread-heap statistics into the heap after this many bytes; 0 disables
    ArenaPurgeImmediateSize arena_purge_immediate_size 32 MiB (in KiB) see point 3; get_size() returns bytes

    The four Profile* options only matter when MIMALLOC_PROFILE is set, and are read once at process start (use the environment variables). StatsMergeThreshold and ArenaPurgeImmediateSize are read on every use.

  • Documentation updated to the 3.6.0 behaviour: PurgeDelay, ArenaPurgeMult, ArenaPurgeMinSize and collect now mention the immediate purge of large ranges; PageReclaimOnFree states the new default and that set from main has no effect on the global allocator's heap; AllowThp notes the over-8 MiB huge page case; the README tuning table has rows for ArenaPurgeImmediateSize and PageReclaimOnFree.

  • Version: 3.6.0. The +1 revision suffix of v3.5.3+1 is dropped, because the upstream version moved. The Rust API otherwise matches v3.5.3+1: MiMalloc, usable_size, process_info, collect, and the secure, override and no_thp features.

  • cc: Cargo.toml still requires cc = "1.8" (the minimum, so consumers are not forced to a newer cc); Cargo.lock now pins cc 1.10.0 (was 1.9.0).

  • process_info() and collect() are unchanged. I compared the C implementations of mi_process_info and mi_collect with 3.5.3; they are identical on Unix, macOS and WASI, and the Windows version differs only in a string literal. The table of sources in the ProcessInfo rustdoc still holds.

  • Tested on Linux x86-64 in debug and release, and with the secure, override and no_thp features (option names/discriminants against mi_options_print_out, set/get round trip, process_info, and RSS going back down after freeing 400 MiB), plus cargo clippy and cargo doc. Not tested on Windows, macOS, 32-bit or other targets in this release.

What changed in mimalloc 3.5.3 → 3.6.0 (upstream)

Upstream summary (its readme): "(v3) add initial profiling hooks and default profiler, "always on" detailed statistics per size-bin, and always-on profiling. Initial rust bindings. Better support for large OS page sizes, support a quiescent state based reclamation interface (for CPython), better cache line aware allocation, fix heap visitor where some pages might be skipped, improve fork support, avoid over-allocation for naturally aligned allocations, fix stderr console output for XBox, fix huge allocation rollback, refactor the source and include files, immediately purge very large allocations, fix bcrypt dependency on windows, fix heap-destroy bug when a fresh heap was allocated at the same address (giving a segfault), page_reclaim_on_free is now on by default."

Full list: microsoft/mimalloc@v3.5.3...v3.6.0. The parts below are grouped by what they mean for a user. Items marked (C API) are in mimalloc.h but not wrapped by this crate; items marked (CMake) are upstream build options that this crate's build.rs does not use.

Behaviour and defaults

  • page_reclaim_on_free is on by default (cross-thread reclaim on free); the option is now a per-heap creation default. See point 2 above.
  • Freed ranges of at least 32 MiB are purged immediately (arena_purge_immediate_size); an explicit mi_arenas_purge() (C API) was added (upstream issue #1422). Purging is also allowed in arena_free (PR #1448).
  • Options renamed (guarded_precise → unsafe_guarded_precise, minimal_purge_size → arena_purge_min_size, collect_merges_stats → stats_merge_on_collect), new options for the profiler, stats_merge_threshold and arena_purge_immediate_size. guarded_sample_rate now means "guard an object about every N requested bytes" (was "1 out of N allocations"); its default stays 0 and it only matters with MI_GUARDED, which this crate does not enable.
  • Small blocks get a cache offset based on a hash of the page; large allocations get a cache offset as well; 64 KiB blocks move into large pages (issues #1121; PR #1339).
  • page_full_retain adapts when cross-thread frees revive full pages. Stat merging between thread heaps and the heap was reworked (a regression from it was fixed).
  • No over-allocation for naturally aligned requests (PR #1408); the "naturally aligned" condition was relaxed and is checked in debug builds.
  • On Windows, stderr output no longer attaches to the parent console.

Profiling and statistics

  • Built-in pprof heap profiler (protobuf and text formats), activated by MIMALLOC_PROFILE, with allocation/in-use/time interval snapshots, a custom allocation-hook API (mimalloc-profile.h), mapped-libr...
Read more

v3.5.3+1

Choose a tag to compare

@amsokol amsokol released this 21 Oct 15:37
v3.5.3+1
e68e3f3

Expose mimalloc options and process info to safe Rust; still mimalloc v3.5.3, build dependency cc 1.9

  • mimalloc::Option: every non-deprecated mimalloc option, with get, set, is_enabled, set_enabled, get_size, name and Option::ALL; the rustdoc of each says when mimalloc reads it
  • mimalloc::process_info() -> ProcessInfo (time, current/peak RSS, current/peak commit, page faults) and mimalloc::collect(force)
  • no_thp feature: transparent huge pages off from process start (MI_DEFAULT_ALLOW_THP=0), since allow_thp set from main cannot undo what mimalloc does before main
  • README: API and a tuning section (purge_delay 0 and no_thp for long-running processes)

Full Changelog: v3.5.3...v3.5.3+1

v3.5.3

Choose a tag to compare

@amsokol amsokol released this 17 Sep 06:01
v3.5.3
ce6fe62

Update dependencies to mimalloc v3.5.3; adjust Cargo files and README

Full Changelog: v3.5.2...v3.5.3

v3.5.2

Choose a tag to compare

@amsokol amsokol released this 14 Sep 18:55
v3.5.2
e08e549

Update dependencies to mimalloc v3.5.2 and cc v1.4.6; adjust Cargo files and README

Full Changelog: v3.5.1...v3.5.2

v2.5.2

Choose a tag to compare

@amsokol amsokol released this 14 Sep 18:52
v2.5.2
638b99d

Update mimalloc dependency to version 2.5.2 and cc to version 1.4.6 in Cargo.toml and Cargo.lock, and adjust README to reflect the new version. Update submodule reference for mimalloc.

Full Changelog: v2.5.1...v2.5.2

v1.15.2

Choose a tag to compare

@amsokol amsokol released this 14 Sep 18:49
v1.15.2
d8a3192

Update mimalloc to version 1.15.2 and cc to version 1.4.6. Modify README to reflect the new version tags and update Rust bindings documentation accordingly. Ensure compatibility with the latest features and improvements.

Full Changelog: v1.15.1...v1.15.2

v3.5.1

Choose a tag to compare

@amsokol amsokol released this 02 Sep 21:46
v3.5.1
1ea5e86

Full Changelog: v3.5.0...v3.5.1

v2.5.1

Choose a tag to compare

@amsokol amsokol released this 02 Sep 21:37
v2.5.1
9aa07ef

Full Changelog: v2.5.0...v2.5.1

v1.15.1

Choose a tag to compare

@amsokol amsokol released this 02 Sep 14:48
v1.15.1
479c264

Update mimalloc to version 1.15.1. Modify README to reflect the new version tags and update Rust bindings documentation accordingly. Ensure compatibility with the latest features and improvements.

v3.5.0

Choose a tag to compare

@amsokol amsokol released this 20 Aug 11:45
v3.5.0
5407006

Full Changelog: v3.4.5...v3.5.0