Skip to content

feat: add optional jemalloc global allocator (#402) - #417

Open
mwiewior wants to merge 1 commit into
masterfrom
feat/jemalloc-allocator
Open

feat: add optional jemalloc global allocator (#402)#417
mwiewior wants to merge 1 commit into
masterfrom
feat/jemalloc-allocator

Conversation

@mwiewior

@mwiewior mwiewior commented Jul 1, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds an opt-in jemalloc Cargo feature (off by default) that installs
tikv-jemallocator as the global
allocator. Addresses #402.

  • Off by default — enable with maturin build --features jemalloc (Linux/macOS).
  • Gated to non-MSVC targets (cfg(not(target_env = "msvc"))), so Windows keeps the
    system allocator (tikv-jemallocator doesn't support MSVC).
  • Default builds are byte-identical to before — no allocator is compiled in unless
    the feature is enabled.
#[cfg(all(feature = "jemalloc", not(target_env = "msvc")))]
#[global_allocator]
static GLOBAL: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc;

Why jemalloc (and not mimalloc)

I benchmarked default vs mimalloc vs jemalloc on the single-thread interval-operation
suite (databio, 8 operations, POLARS_MAX_THREADS=1, -C target-cpu=native, macOS
arm64). Two reasons jemalloc wins:

  1. jemalloc is faster and leaner. Runtime geomean −12.3% vs default, with
    equal-or-lower peak RSS. mimalloc was faster too (−9.3%) but cost +36–40% peak RSS
    on reduce ops (merge/complement) because it retains freed segments.
  2. mimalloc v3 (the crate default) segfaults at import on macOS arm64 — a load-time
    EXC_BAD_ACCESS in mi_bbitmap_try_find_and_clear. It only works if pinned to the
    v2 feature. jemalloc has no such issue.

Runtime, vs default (geomean of per-case ratios)

operation jemalloc Δ%
merge −23.5%
count_overlaps −17.6%
coverage −16.1%
cluster −12.8%
complement −12.0%
nearest −7.0%
overlap −4.1%
subtract −2.3%
overall −12.3%

Peak memory (whole-run RSS, identical workload)

allocator peak Δ vs default
default (system) 14.95 GiB baseline
jemalloc 14.19 GiB −5.0%
mimalloc v2 21.19 GiB +41.8%

Numbers are macOS-laptop, single-thread, directional — macOS libmalloc is slow, so
the win overstates a Linux release build. Full data (per-op runtime + per-op peak/avg
RSS) lives in the polars-bio-bench repo (results/alloc-impact-summary.md).

Verification

  • RUSTFLAGS="-Dwarnings" cargo check (default) and --features jemalloc both clean.
  • Built the --features jemalloc wheel and confirmed import polars_bio + an overlap
    run succeed on macOS arm64.

Follow-ups (not in this PR)

  • Since the feature is off by default, the published PyPI wheels do not include it.
    To ship jemalloc to end users, add --features jemalloc to the maturin args in the
    Linux/macOS jobs of .github/workflows/publish_to_pypi.yml (leave Windows untouched).
  • A Linux, ideally multi-threaded, confirmation run is worth doing before flipping it
    on in wheels — multithreaded allocation is where jemalloc typically helps most.

🤖 Generated with Claude Code

Adds a `jemalloc` Cargo feature (off by default) that installs
tikv-jemallocator as the global allocator on Linux/macOS. Gated to
non-MSVC targets, so Windows keeps the system allocator. Default builds
are byte-identical to before.

On the single-thread interval-operation benchmark suite jemalloc was
~12% faster (geomean) with equal-or-lower peak RSS than the default
system allocator.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@mwiewior
mwiewior force-pushed the feat/jemalloc-allocator branch from 933d18d to 0b07f2b Compare July 1, 2026 08:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant