328 Commits
Author SHA1 Message Date
YANG XIN 250120f25f Fix thread.tcache.max when tcache is disabled at startup
Starting with MALLOC_CONF=tcache:false and reading or writing
thread.tcache.max before first enabling the cache dereferences NULL.

The tcache_t embedded in TSD always exists, but tcache->tcache_slow is
assigned only by tcache_init(), which is skipped in this case. The
tcache_slow settings embedded in TSD are initialized independently.
Disabling an already initialized cache does not encounter this missing
link, since tcache_init() has already run.

Read and update the embedded settings through tsd_tcache_slowp_get().
This allows configuring the limit before the first enable without
initializing the cache as a side effect.

Add a fresh-thread regression covering the initial read, update while
disabled, and preservation of the limit on first enable. A standalone
public-API program also reproduces the original crash with tcache:false
against a release library.
2026-10-02 17:43:36 -04:00
1234binpig 344b5eb353 build: prioritize in-tree headers over installed jemalloc headers and tests: cover installed header precedence
* build: prioritize in-tree jemalloc headers
* tests: cover installed header precedence

Signed-off-by: huangwenbin <huangwenbin@kylinos.cn>
2026-10-01 16:36:53 -07:00
Slobodan Predolac 62b1a27903 Map per-CPU arenas through a boot-time table
percpu_arena_choose() returned an unclamped sched_getcpu(), so a process
confined to a subset of CPUs got arena indices past the end of the auto
range. Such arenas are invisible to the stats and ctl paths, which
iterate only to narenas_total_get(), and with a small narenas the index
could instead collide with huge_arena_ind and route ordinary
allocations into the oversize arena. Choose the arena through a table
built once at boot: CPUs the boot affinity mask allows are ranked so
each gets its own arena and every index stays inside the auto range.
2026-09-17 18:57:36 -04:00
Slobodan Predolac fad15aaf64 Refactor per-CPU arena helpers 2026-09-17 18:57:36 -04:00
Azat Khuzhin 61dc1da395 Fix possible tcache corruption on fiber migration (under --enable-experimental-fiber-safe-tls)
Under LTO `&tsd_tls` is hoisted out of the inlined malloc/free and
survives swapcontext in a callee-saved register: a fiber resumed on
another OS thread races on the old thread's tcache.

Fix it by taking the address in a noinline volatile-asm barrier accessor.

It is done under option (--enable-experimental-fiber-safe-tls), because
it make the fastpath slower, on a microbench (that is very heavy depends
on the most optimal case) the overhead is 35%, but this is unlikely the
real world scenario.

Anyway here are some numbers for microbench.c compiled with LTO:

type    |vanilla (ns)|`--enable-experimental-fiber-safe-tls` (ns)|optimized (ns) [1]
--------|------------|-------------------------------------------|------------------
malloc  |6.51        |8.77 **(+34%)**                            |6.79 (4%)
mallocx |8.48        |10.62 **(25%)**                            |8.76 (3%)
free    |6.46        |8.68 **(34%)**                             |6.76 (5%)
dallocx |8.190       |10.97 **(33%)**                            |8.74 (7%)

  [1]: https://github.com/jemalloc/jemalloc/pull/2944

This patch also adds a separate lane for CI with LTO
2026-09-01 22:10:15 -04:00
Slobodan Predolac d13fe91afd Adapt tcache fill and retention
Replace divisor-based small-bin refill control and fixed GC flushing
with per-bin fill and retention targets based on use between GC events.
Keep the bounds valid for all configured capacities, and ensure a
full-bin flush always frees a slot.

Simplify the configuration space by removing and deprecating
experimental_tcache_gc, lg_tcache_nslots_mul,
tcache_nslots_small_min, tcache_nslots_small_max, tcache_nslots_large,
tcache_gc_delay_bytes, lg_tcache_flush_small_div, and
lg_tcache_flush_large_div. Per-size-class cache capacity remains
configurable through tcache_ncached_max.
2026-09-01 11:51:32 -04:00
Tony Printezis e36a0fa5bc Fix prof-sampling / guard-page interaction bug in the SAN
Due to an incorrect condition, a prof-promoted small allocation
was incorrectly wrapped in large-extent guard pages. This consumed
the large-guard budget, so the next genuinely large allocation that
should have been guarded got skipped.
2026-08-10 09:16:09 -04:00
Tony Printezis abb0a8a05b Fix compilations warnings on MacOS. 2026-07-31 16:51:05 -07:00
Tony Printezis c597d73778 Remove frameptr-based unwinder.
The frameptr-based unwinder was an interim solution while issues with
libunwind were resolved. It's better if we remove it,
so we don't have to support it moving forward.
2026-07-18 11:51:02 -07:00
guangli-dai e931730f51 Add PAC decay/deferral unit test coverage.
Add unit tests to cover public interface of pac decay & deferral
relevant functions.  To align with the decopuling between arena and pac,
rename arena_decay to pac_decay here.
2026-07-16 21:52:34 -07:00
Raúl MarínandClaude Opus 4.8 68c35f6557 Allow resuming per-CPU arena selection via thread.arena (#2957)
* Allow resuming per-CPU arena selection via thread.arena

With percpu_arena enabled, thread.arena control is one-directional. A
thread can be bound to a manually created arena (an index at or above the
per-CPU auto range) to route a bounded region of work to a dedicated,
long-lived arena, but there is no way back: thread_arena_ctl returns EPERM
for any index within the auto range, and arena_choose_impl only re-selects
a per-CPU arena for threads whose current arena is already in that range.
So once a thread is bound to a manual arena it stays pinned there forever,
and its later allocations land there instead of following the CPU.

Treat setting thread.arena to an index within the per-CPU range as a
request to resume automatic per-CPU selection: hand the thread back to
percpu management (rebinding it to the current CPU's arena via
percpu_arena_update) and return 0 instead of EPERM. Binding to a manual
arena is unchanged. The requested index is advisory; under percpu the
thread is governed by its current CPU, so it resumes on the current CPU's
arena regardless of the value passed.

Add test/unit/percpu_arena_resume covering the manual-arena to resume
round trip with allocs & dallocs happening meanwhile, and update 
test_thread_arena, which asserted the old EPERM.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-16 14:53:25 -07:00
Farid Zakaria b859093d28 Limit TSD bootstrap hook to tests 2026-07-06 18:26:40 -04:00
Farid Zakaria 7c34a482c1 Add TSD reentrant stress test 2026-07-06 18:26:40 -04:00
Bruno Gonçalves 7ce8b9165d Accept NULL in free_sized() and free_aligned_sized()
free_sized() and free_aligned_sized() forward straight to sdallocx(), which
expects a non-NULL pointer and asserts on it in debug builds. C23 says both
should accept NULL and do nothing, like free(NULL) does, so a NULL argument
either trips that assert or feeds NULL into the dealloc path in release builds.

It is not hard to hit. glibc 2.41 ships free_sized()/free_aligned_sized(), and
a C++ sized delete of a null pointer compiles down to a free_sized() call. Once
jemalloc is preloaded its versions take over, and that NULL call takes down the
process. I ran into it with GTK4/GLib apps under LD_PRELOAD.

Check for NULL first, the way free() already does, and add an integration test
covering the NULL case for both functions.

While here, give free_aligned_sized() its own core.free_aligned_sized.entry
and .exit logging and call je_sdallocx_impl() directly rather than the
je_sdallocx() wrapper, so it mirrors free_sized() and no longer logs under
sdallocx. The C++ sized-delete paths (sizedDeleteImpl, alignedSizedDeleteImpl)
get the same treatment: log entry/exit unconditionally and guard the call with
likely(ptr != nullptr).
2026-06-29 16:35:49 -04:00
Bin Liu 9c1a484e1d Use SEC in PAC to reduce lock contention on the ecaches
Add a small extent cache in front of the PAC ecaches. Allocs and dallocs
that fit are served from per-shard SEC bins without taking the ecache
mutex; overflow falls through to the backing ecaches, including
ecache_pinned for pinned extents.

The feature is gated behind experimental_pac_sec_nshards (default 0,
disabled). To support independent HPA and PAC SEC instances,
sec_alloc/sec_dalloc/sec_fill take an explicit shard argument, with HPA
and PAC using separate TSD shard slots.
2026-06-24 10:54:34 -07:00
Slobodan Predolac 160ab9d7f6 Replace experimental_infallible_new with compile-time flag
The runtime option aborted on every OOM, breaking new(std::nothrow)
semantics. Replace with configure-time --enable-cxx-infallible-new
(default off): when on, throwing new aborts (size logged) and
nothrow returns null; when off, standard new_handler + bad_alloc /
null behavior is preserved. Under LTO the on-path lets the compiler
prove operator new is no-throw.
2026-06-06 09:50:37 -04:00
Slobodan Predolac 9d75722344 Move malloc routing into new malloc_dispatch module
Pull the tcache-aware routing helpers out of arena into a layer that
sits directly below the public malloc interface:

  arena_malloc           -> malloc_dispatch_malloc
  arena_palloc           -> malloc_dispatch_palloc
  arena_ralloc           -> malloc_dispatch_ralloc
  arena_dalloc*          -> malloc_dispatch_dalloc*
  arena_sdalloc*         -> malloc_dispatch_sdalloc*
  arena_dalloc_promoted  -> malloc_dispatch_dalloc_promoted

The new module (malloc_dispatch.h, malloc_dispatch_inlines.h,
src/malloc_dispatch.c) owns the tcache-vs-fall-through decision; the
only consumer is jemalloc_internal_inlines_c.h.  arena keeps a narrower
arena_prof_demote() for the sampled-allocation demotion path.
2026-06-04 11:32:53 -04:00
Slobodan Predolac 716bda4394 Improve unit test coverage in tcache, pac, hpa_central 2026-06-01 18:18:31 -04:00
Slobodan Predolac c5a1822d69 Remove batch_alloc API 2026-05-22 23:34:10 -07:00
Bin Liu a5db9feee5 Fix psset_enumerate_search pages-vs-bytes comparison 2026-05-21 13:07:08 -07:00
Slobodan Predolac ff2c2548a3 Remove generic experimental hooks 2026-05-13 18:27:43 -04:00
Slobodan Predolac 163c871d6c Add DSS allocation path unit tests 2026-05-12 13:14:39 -04:00
Bin Liu be2de8ccd8 Introduce pinned extents to contain unpurgeable pages
Some pages (e.g., hugetlb pages) cannot be purged, and should be
prioritized for reuse.  A custom extent_alloc hook signals this by
OR'ing EXTENT_ALLOC_FLAG_PINNED into the low bits of the returned
pointer; jemalloc strips the flag bits and caches pinned extents in
a dedicated ecache_pinned, separate from the dirty/muzzy decay
pipeline.

Pinned extents do not coalesce eagerly, except for ones larger than
SC_LARGE_MINCLASS.  A prefer-small policy reuses the smallest fitting
pinned extent, to avoid unnecessary split/fragmentation.
2026-05-05 10:44:28 -07:00
Slobodan Predolac 6e0b8e6daa Improve unit test coverage for jemalloc_init, arenas_management, and jemalloc_fork modules 2026-04-30 15:17:18 -04:00
Slobodan Predolac ba1e2fe4db Extract fork orchestration into jemalloc_fork module 2026-04-30 15:17:18 -04:00
Slobodan Predolac ec07fc3c5f Extract initialization logic from jemalloc.c into jemalloc_init module 2026-04-30 15:17:18 -04:00
Slobodan Predolac e0a8401533 Extract arena state and management from jemalloc.c into arenas_management module 2026-04-30 15:17:18 -04:00
lexprfuncall 1a15fe33a4 Replace std::__throw_bad_alloc call with standard C++ (#2900)
* Replace std::__throw_bad_alloc call with standard C++

Since December of 2025, std::__throw_bad_alloc is no longer visible
through #include <new> causing jemalloc build failures with gcc 16.
As far as I can tell, all std::__throw_bad_alloc did was arrange to
raise a std::bad_alloc exception if exceptions are enabled.  I am not
sure whether its usage was truly meaningful in jemalloc since the call
is wrapped in a try catch and any usage of try catch is considered an
error when compiling with -fno-exceptions on gcc, at least.

This change adds a check to configure.ac that determines whether
exceptions are enabled by compiling a simple try catch that raises a
std::bad_alloc exception.  If that test succeeds, the macro
JEMALLOC_HAVE_CXX_EXCEPTIONS is defined, and jemalloc will raise an
exception.  Otherwise, we call std::terminate() to abort.

This was tested on FreeBSD with the gcc16 port with and without exceptions
enabled.

* Replace std::set_new_handler calls with std::get_new_handler

Previously, std::set_new_handler was used as a workaround for
compilers with only partial support for C++11.  Now that C++14 is a
requirement to enable C++ support, we can assume std::get_new_handler
is available.
2026-04-27 11:50:27 -07:00
guangli-dai bb0a6aca10 Allow spaces in prefix. 2026-04-27 09:59:59 -07:00
Integral 1f44a8b11d Change permission modes of static libraries to 644 (#2885)
Static libraries are archives and do not need the executable bit.
2026-04-19 14:13:02 -07:00
Slobodan Predolac a0f2bdf91d Fix missing negation in large_ralloc_no_move usize_min fallback
The second expansion attempt in large_ralloc_no_move omitted the !
before large_ralloc_no_move_expand(), inverting the return value.
On expansion failure, the function falsely reported success, making
callers believe the allocation was expanded in-place when it was not.
On expansion success, the function falsely reported failure, causing
callers to unnecessarily allocate, copy, and free.

Add unit test that verifies the return value matches actual size change.
2026-04-01 23:15:19 -04:00
Carl Shapiro 86b7219213 Add unit tests for conf parsing and its helpers 2026-03-10 18:14:33 -07:00
Carl Shapiro ad726adf75 Separate out the configuration code from initialization 2026-03-10 18:14:33 -07:00
Carl Shapiro a056c20d67 Handle tcache init failures gracefully
tsd_tcache_data_init() returns true on failure but its callers ignore
this return value, leaving the per-thread tcache in an uninitialized
state after a failure.

This change disables the tcache on an initialization failure and logs
an error message.  If opt_abort is true, it will also abort.

New unit tests have been added to test tcache initialization failures.
2026-03-10 18:14:33 -07:00
Carl Shapiro a75655badf Add unit test coverage for bin interfaces 2026-03-10 18:14:33 -07:00
guangli-dai c73ab1c2ff Add a test to check the output in JSON-based stats is consistent with mallctl results. 2026-03-10 18:14:33 -07:00
Slobodan Predolac 34ace9169b Remove prof_threshold built-in event. It is trivial to implement it as user event if needed 2026-03-10 18:14:33 -07:00
Andrei Pechkurov 4d0ffa075b Fix background thread initialization race 2026-03-10 18:14:33 -07:00
Slobodan Predolac 6016d86c18 [SEC] Make SEC owned by hpa_shard, simplify the code, add stats, lock per bin 2026-03-10 18:14:33 -07:00
Slobodan Predolac 8a06b086f3 [EASY] Extract hpa_central component from hpa source file 2026-03-10 18:14:33 -07:00
Slobodan Predolac 355774270d [EASY] Encapsulate better, do not pass hpa_shard when hooks are enough, move shard independent actions to hpa_utils 2026-03-10 18:14:33 -07:00
Slobodan Predolac 3678a57c10 When extracting from central, hugify_eager is different than start_as_huge 2026-03-10 18:14:33 -07:00
guangli-dai 261591f123 Add a page-allocator microbenchmark. 2026-03-10 18:14:33 -07:00
guangli-dai 56cdce8592 Adding trace analysis in preparation for page allocator microbenchmark. 2026-03-10 18:14:33 -07:00
Carl Shapiro daf44173c5 Replace an instance of indentation with spaces with tabs 2026-03-10 18:14:33 -07:00
Shirui Cheng 2114349a4e Revert PR #2608: Manually revert commits 70c94d..f9c0b5
Closes: #2707
2026-03-10 18:14:33 -07:00
Slobodan Predolac e6864c6075 [thread_event] Remove macros from thread_event and replace with dynamic event objects 2026-03-10 18:14:33 -07:00
Jason Evans 27d7960cf9 Revert "Extend purging algorithm with peak demand tracking"
This reverts commit ad108d50f1.
2025-06-02 10:44:37 -07:00
Slobodan Predolac 1956a54a43 [process_madvise] Use process_madvise across multiple huge_pages 2025-04-25 19:19:03 -07:00
Slobodan Predolac f19f49ef3e if process_madvise is supported, call it when purging hpa 2025-04-04 13:57:42 -07:00