Jemalloc was just removed from the standard library 🎉

Until now, rustc implicitly linked the jemalloc memory allocator to every Rust program (not staticlib or cdylib libraries) by default on some platforms (including Linux and macOS). jemalloc is often more performant than the system’s allocator, but not always, and it adds a non-trivial amount to the size of the executable.

In Rust 1.28, we stabilized the #[global_allocator] attribute that allows a program to opt into another memory allocator, and the std::alloc::System type to represent the system’s default allocator.

PR #55238 has landed today, removing jemalloc from the Rust standard library. So starting with tomorrow’s Rust Nightly, Rust programs will use the system allocator by default. You can use the jemallocator crate together with #[global_allocator] if you want to keep using jemalloc.

Changing the default took a long time because it was tricky to figure out a way to do it while still using jemalloc in rustc and LLVM-in-rustc, because of the unusual way rustc is linked. See issues #36963 and #51038 for more background. jemalloc is a significant performance improvement in almost all cases for rustc’s workloads.

24 Likes

FYI, the jemallocator crate makes using jemalloc as the global allocator as easy as adding it as a dependency and then setting it as the global allocator:

#[global_allocator] 
static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;

Just keep in mind that jemalloc does not support all targets that rustc supports (it supports many though), and that until now rustc implicitly selected a different allocator if jemalloc was not available for a target. Now you will have to explicitly fall back to the system allocator in those targets by #[cfg()] jemallocator away.

7 Likes

Perhaps the jemallocator readme can keep an updated #[cfg] for the targets it supports so it’s easy to copy/paste that without failing to compile on random platforms?

6 Likes

So how does this work? I can see that System is set as default allocator on stage 0, but how/where is System set as the “magic fallback” that happens when no allocator is set?

@ahmedcharles I wanted to add a crate to the jemallocator repo that just sets jemallocator as the #[global_allocator] for you, so that the only thing one has to do is add that crate as a dependency and “that’s it”.

We can set that crate up so that it does nothing on platforms that are not supported by jemalloc (e.g. by being empty), and add an opt-in feature to it that produces a compile_error! instead.

That would allow you to choose whatever behavior you want with little effort, and either just fall back to the system allocator, or add some other crate specifying some other #[global_allocator] on those platforms without collisions (there can only be one #[global_allocator] in a program).

@SimonSapin @Sfackler do you think that something like this might be a good idea?

The compiler is the one that selects which allocator is in use, and deep within it you’ll find logic that looks for #[global_allocator] and, failing that, will use some symbols defined in the standard library instead. It’s… a bit complicated and convoluted how this is implemented, but thankfully not too relevant to users!

So it hard-codes a path to fall back to? I was sure there'd have to be a lang item for this, but I guess not.^^

Not a path, but literally unmangled symbol names.

Allocation APIs call some extern functions declarations with known symbol names. For “leaf” (non-rlib) creates, the compiler generates these functions to call either the extern function definitions generated by #[global_allocator], or the differently-named definitions in std.

I like the idea of a feature in jemallocator itself that will register it as the global allocator.

A separate crate for “jemalloc when supported” seems like a neat idea as well.

This might seem like a strange question, but does the jemallocator crate work on the wasm32-unknown-unknown target?

I’m not sure, but jemalloc was not previously used for that target, so if it doesn’t, it’s not a regression, just a bug.

wasm targets are not affected by this change. They use a Rust port of dlmalloc by default. I don’t know if anyone has tried to compile jemalloc’s C code to wasm an make it work in that environment.

1 Like

I’ve filed a bug report:

This should make using valgrind with Rust a works-out-of-the-box experience! Thanks :hearts:

2 Likes

This should make using valgrind with Rust a works-out-of-the-box experience!

Could you clarify why removing jemalloc makes it easier to run valgrind? I've been using valgrind for a while now. (It's how I noticed that the allocator changed! :stuck_out_tongue: )

The old bundled jemalloc didn’t support valgrind’s instrumentation.

1 Like

The old bundled jemalloc didn’t support valgrind’s instrumentation.

Sorry, I'm rather new to Valgrind so I'm not sure what I'm missing. What instrumentation wasn't supported? Is the output different now?

Jemalloc has made changes that make it so valgrind can’t tell what’s going on:

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.