Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
afa6c90
set _mi_process_is_initialized before mi_process_setup_auto_thread_done
Brooooooklyn Sep 14, 2026
442ed88
fix: safely free over-aligned small allocations
shubhambhar007 Sep 14, 2026
9c36a82
Merge pull request #1401 from shubhambhar007/fix/1400-free-size-aligned
daanx Sep 14, 2026
8f8e2d0
add a counter to xthread_free to reduce reclamation rate
daanx Sep 14, 2026
32a782f
update documentation for mi_free_size_aligned
daanx Sep 14, 2026
e8621a7
clean up csize functions
daanx Sep 15, 2026
8bf7820
revise handling of NULL theaps using xtheap naming convention; fixes …
daanx Sep 15, 2026
cc1df5e
Merge pull request #1399 from napi-rs/fix/process-init-flag-before-th…
daanx Sep 15, 2026
a09da20
fix recursion
daanx Sep 15, 2026
e2f06aa
weaken assertion
daanx Sep 15, 2026
d8913a5
fix syntax
daanx Sep 15, 2026
d1e9bf4
temporarily only reclaim when the counter is 1
daanx Sep 15, 2026
fe94a2d
temporarily only reclaim when the counter is 1
daanx Sep 15, 2026
d184163
make page->theap atomic so we can read it unowned
daanx Sep 15, 2026
b1034d6
Revert "make page->theap atomic so we can read it unowned"
daanx Sep 15, 2026
8b3a5c3
revert to using a plain xthread_free without a counter
daanx Sep 15, 2026
5e4b2ce
revise once more the non-null theap allocation variants; reduce cases…
daanx Sep 16, 2026
014be9a
disable MEMZERO16X for now on riscV (due to compiler errors)
daanx Sep 16, 2026
d47c4ca
bump version v3.5.3
daanx Sep 16, 2026
4477714
fix bitmap ccount calculation
daanx Sep 16, 2026
8352ee2
update readme
daanx Sep 16, 2026
8c377a9
fix msbuild multi config
daanx Sep 16, 2026
a2d339d
add extra heap alignment test
daanx Sep 16, 2026
326d271
update readme
daanx Sep 16, 2026
53bbb1f
update readme
daanx Sep 16, 2026
d4881d3
fix arena allocation for exclusive child arenas, PR #1404
daanx Sep 17, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ permissions:
contents: write

env:
RELEASE: Release v3.5.2
RELEASE: Release v3.5.3
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true

name: Release
Expand All @@ -19,7 +19,7 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
branch: [v3.5.2, v2.5.2, v1.15.2] # [dev,dev2,dev3]
branch: [v3.5.3, v2.5.2, v1.15.2] # [dev,dev2,dev3]
# we build on the oldest ubuntu version for better binary compatibility.
os: [windows-latest, macOS-latest, macos-15-intel, ubuntu-22.04, ubuntu-22.04-arm]

Expand Down
24 changes: 21 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -931,6 +931,8 @@ endif()
if(MI_TRACK STREQUAL "ASAN")
set(mi_libname "${mi_libname}-asan")
endif()
set(mi_libname_base "${mi_libname}") # capture the base name (without any per-config suffix)

if (CMAKE_CONFIGURATION_TYPES)
# multi-config builds
# generator expression lower-case build type
Expand Down Expand Up @@ -1008,7 +1010,23 @@ if(MI_BUILD_SHARED)
# so we postfix the dll import library with `.dll.lib` (and also the .pdb debug file)
set_property(TARGET mimalloc PROPERTY ARCHIVE_OUTPUT_NAME "${mi_libname}.dll" )
install(FILES "$<TARGET_FILE_DIR:mimalloc>/${mi_libname}.dll.lib" DESTINATION ${CMAKE_INSTALL_LIBDIR}/mimalloc-${mi_version})
set_property(TARGET mimalloc PROPERTY PDB_NAME "${mi_libname}.dll")
if (CMAKE_CONFIGURATION_TYPES)
# PDB_NAME only supports generator expressions since CMake 4.1; for multi-config
# generators (like Visual Studio) we instead set `PDB_NAME_<CONFIG>` for each
# known configuration explicitly (mirroring the release/debug suffix logic above).
foreach(mi_cfg IN LISTS CMAKE_CONFIGURATION_TYPES)
string(TOUPPER "${mi_cfg}" mi_cfg_uc)
string(TOLOWER "${mi_cfg}" mi_cfg_lc)
if (mi_cfg_lc MATCHES "^(release|relwithdebinfo|minsizerel|none)$")
set(mi_libname_pdb "${mi_libname_base}")
else()
set(mi_libname_pdb "${mi_libname_base}-${mi_cfg_lc}")
endif()
set_property(TARGET mimalloc PROPERTY "PDB_NAME_${mi_cfg_uc}" "${mi_libname_pdb}.dll")
endforeach()
else()
set_property(TARGET mimalloc PROPERTY PDB_NAME "${mi_libname}.dll")
endif()
# don't try to install the pdb since it may not be generated depending on the configuration
# install(FILES "$<TARGET_FILE_DIR:mimalloc>/${mi_libname}.dll.pdb" DESTINATION ${CMAKE_INSTALL_LIBDIR})
endif()
Expand Down Expand Up @@ -1151,7 +1169,7 @@ if (MI_BUILD_TESTS)
endforeach()

# static override test
if(MI_BUILD_OBJECT AND NOT (MI_CYGWIN OR (MI_TRACK STREQUAL "ASAN") OR MI_DEBUG_TSAN OR MI_DEBUG_UBSAN))
if(MI_BUILD_OBJECT AND MI_OVERRIDE AND NOT (MI_CYGWIN OR (MI_TRACK STREQUAL "ASAN") OR MI_DEBUG_TSAN OR MI_DEBUG_UBSAN))
add_executable(mimalloc-test-stress-static test/test-stress.c)
target_compile_definitions(mimalloc-test-stress-static PRIVATE ${mi_defines} "USE_STD_MALLOC=1")
target_compile_options(mimalloc-test-stress-static PRIVATE ${mi_cflags})
Expand All @@ -1161,7 +1179,7 @@ if (MI_BUILD_TESTS)
endif()

# dynamic override test
if(MI_BUILD_SHARED AND NOT (MI_CYGWIN OR (MI_TRACK STREQUAL "ASAN") OR MI_DEBUG_TSAN OR MI_DEBUG_UBSAN)) # AND NOT (APPLE AND MI_USE_CXX))
if(MI_BUILD_SHARED AND MI_OVERRIDE AND NOT (MI_CYGWIN OR (MI_TRACK STREQUAL "ASAN") OR MI_DEBUG_TSAN OR MI_DEBUG_UBSAN)) # AND NOT (APPLE AND MI_USE_CXX))
add_executable(mimalloc-test-stress-dynamic test/test-stress.c)
target_compile_definitions(mimalloc-test-stress-dynamic PRIVATE ${mi_defines} "USE_STD_MALLOC=1")
target_compile_options(mimalloc-test-stress-dynamic PRIVATE ${mi_cflags})
Expand Down
2 changes: 1 addition & 1 deletion cmake/mimalloc-config-version.cmake
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
set(mi_version_major 3)
set(mi_version_minor 5)
set(mi_version_patch 2)
set(mi_version_patch 3)
set(mi_version ${mi_version_major}.${mi_version_minor})

set(PACKAGE_VERSION ${mi_version})
Expand Down
2 changes: 1 addition & 1 deletion include/mimalloc-new-delete.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ terms of the MIT license. A copy of the license can be found in the file
void operator delete (void* p, const std::nothrow_t&) noexcept { mi_free(p); }
void operator delete[](void* p, const std::nothrow_t&) noexcept { mi_free(p); }

mi_decl_new(n) void* operator new(std::size_t n) noexcept(false) { return mi_new(n); }
mi_decl_new(n) void* operator new(std::size_t n) noexcept(false) { return mi_new(n); }
mi_decl_new(n) void* operator new[](std::size_t n) noexcept(false) { return mi_new(n); }

mi_decl_new_nothrow(n) void* operator new (std::size_t n, const std::nothrow_t& tag) noexcept { (void)(tag); return mi_new_nothrow(n); }
Expand Down
105 changes: 65 additions & 40 deletions include/mimalloc.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ terms of the MIT license. A copy of the license can be found in the file
#ifndef MIMALLOC_H
#define MIMALLOC_H

#define MI_MALLOC_VERSION 30502 // major + 2 digits minor + 2 digits patch
#define MI_MALLOC_VERSION 30503 // major + 2 digits minor + 2 digits patch

// ------------------------------------------------------
// Compiler specific attributes
Expand Down Expand Up @@ -396,43 +396,6 @@ mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_theap_zalloc_aligned(
mi_decl_nodiscard mi_decl_export void* mi_theap_realloc(mi_theap_t* theap, void* p, size_t newsize) mi_attr_noexcept mi_attr_alloc_size(3);
mi_decl_nodiscard mi_decl_export void* mi_theap_rezalloc(mi_theap_t* theap, void* p, size_t newsize) mi_attr_noexcept mi_attr_alloc_size(3);

// ------------------------------------------------------
// Fast constant size allocations.
// ------------------------------------------------------

// Machine word size allocation. `wsize` is the allocation size in machine words (`sizeof(size_t)`)
mi_decl_nodiscard mi_decl_restrict void* mi_wzalloc_small(size_t wsize) mi_attr_noexcept;
mi_decl_nodiscard mi_decl_restrict void* mi_wmalloc_small(size_t wsize) mi_attr_noexcept;
mi_decl_nodiscard mi_decl_restrict void* mi_theap_wmalloc_small(mi_theap_t* theap, size_t wsize) mi_attr_noexcept;
mi_decl_nodiscard mi_decl_restrict void* mi_theap_wzalloc_small(mi_theap_t* theap, size_t wsize) mi_attr_noexcept;

// get the machine word size from a byte size.
static inline size_t mi_wsize_from_size(size_t size) {
return ((size + sizeof(size_t) - 1) / sizeof(size_t));
}

static inline mi_decl_restrict void* mi_malloc_csize(size_t size) mi_attr_noexcept {
if (size <= MI_SMALL_SIZE_MAX) { return mi_wmalloc_small(mi_wsize_from_size(size)); } else { return mi_malloc(size); }
}
static inline mi_decl_restrict void* mi_zalloc_csize(size_t size) mi_attr_noexcept {
if (size <= MI_SMALL_SIZE_MAX) { return mi_wzalloc_small(mi_wsize_from_size(size)); } else { return mi_zalloc(size); }
}
static inline mi_decl_restrict void* mi_theap_malloc_csize(mi_theap_t* theap, size_t size) mi_attr_noexcept {
assert(theap!=NULL);
if (size <= MI_SMALL_SIZE_MAX) { return mi_theap_wmalloc_small(theap,mi_wsize_from_size(size)); } else { return mi_theap_malloc(theap,size); }
}
static inline mi_decl_restrict void* mi_theap_zalloc_csize(mi_theap_t* theap, size_t size) mi_attr_noexcept {
assert(theap!=NULL);
if (size <= MI_SMALL_SIZE_MAX) { return mi_theap_wzalloc_small(theap,mi_wsize_from_size(size)); } else { return mi_theap_zalloc(theap,size); }
}
static inline void mi_free_csize(void* p, size_t size) mi_attr_noexcept {
if (size <= MI_SMALL_SIZE_MAX) { mi_free_small(p); } else { mi_free(p); }
}
static inline void mi_free_csize_nonnull(void* p, size_t size) mi_attr_noexcept {
assert(p!=NULL);
if (size <= MI_SMALL_SIZE_MAX) { mi_free_small_nonnull(p); } else { mi_free(p); }
}

// ------------------------------------------------------
// Experimental
// ------------------------------------------------------
Expand Down Expand Up @@ -588,8 +551,13 @@ mi_decl_export int mi_wdupenv_s(wchar_t** buf, size_t* size, const wchar_t* name
mi_decl_nodiscard mi_decl_export mi_decl_restrict wchar_t* mi_wcsdup(const wchar_t* s) mi_attr_noexcept mi_attr_malloc;
mi_decl_nodiscard mi_decl_export mi_decl_restrict unsigned char* mi_mbsdup(const unsigned char* s) mi_attr_noexcept mi_attr_malloc;

// The `mi_new` wrappers implement C++ semantics on out-of-memory instead of directly returning `NULL`.
// (and call `std::get_new_handler` and potentially raise a `std::bad_alloc` exception).
// --------------------------------------------------------
// C++ wrappers
// The `mi_new` wrappers implement C++ semantics on out-of-memory
// instead of directly returning `NULL`. (and call `std::get_new_handler`
// and potentially raise a `std::bad_alloc` exception).
// --------------------------------------------------------

mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_new(size_t size) mi_attr_malloc mi_attr_alloc_size(1);
mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_new_aligned(size_t size, size_t alignment) mi_attr_malloc mi_attr_alloc_size(1) mi_attr_alloc_align(2);
mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_new_nothrow(size_t size) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(1);
Expand All @@ -601,6 +569,63 @@ mi_decl_nodiscard mi_decl_export void* mi_new_reallocn(void* p, size_t newcount,
mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_heap_alloc_new(mi_heap_t* heap, size_t size) mi_attr_malloc mi_attr_alloc_size(2);
mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_heap_alloc_new_n(mi_heap_t* heap, size_t count, size_t size) mi_attr_malloc mi_attr_alloc_size2(2, 3);

mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_theap_alloc_new(mi_theap_t* theap, size_t size) mi_attr_malloc mi_attr_alloc_size(2);
mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_theap_alloc_new_n(mi_theap_t* theap, size_t count, size_t size) mi_attr_malloc mi_attr_alloc_size2(2, 3);
mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_theap_alloc_new_nothrow(mi_theap_t* theap, size_t size) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(2);


// --------------------------------------------------------------------------
// Inlined constant size allocations.
// These are meant for runtime systems, or overrides where we need the best
// performance for small, constant-size allocations.
// These are only better than the regular functions if the size or alignment
// are indeed constant at the call site.
// --------------------------------------------------------------------------

// Internal machine word size allocation. `wsize` is the allocation size in machine words (`sizeof(size_t)`)
mi_decl_nodiscard mi_decl_restrict void* mi_wzalloc_small(size_t wsize) mi_attr_noexcept mi_attr_malloc;
mi_decl_nodiscard mi_decl_restrict void* mi_wmalloc_small(size_t wsize) mi_attr_noexcept mi_attr_malloc;
mi_decl_nodiscard mi_decl_restrict void* mi_theap_wmalloc_small(mi_theap_t* theap, size_t wsize) mi_attr_noexcept mi_attr_malloc;
mi_decl_nodiscard mi_decl_restrict void* mi_theap_wzalloc_small(mi_theap_t* theap, size_t wsize) mi_attr_noexcept mi_attr_malloc;

static inline size_t mi_wsize_from_size(size_t size) mi_attr_noexcept {
return (size + sizeof(size_t) - 1) / sizeof(size_t);
}

static inline mi_decl_restrict void* mi_malloc_csize(size_t size) mi_attr_noexcept {
if (size <= MI_SMALL_SIZE_MAX) { return mi_wmalloc_small(mi_wsize_from_size(size)); } else { return mi_malloc(size); }
}
static inline mi_decl_restrict void* mi_zalloc_csize(size_t size) mi_attr_noexcept {
if (size <= MI_SMALL_SIZE_MAX) { return mi_wzalloc_small(mi_wsize_from_size(size)); } else { return mi_zalloc(size); }
}
static inline mi_decl_restrict void* mi_theap_malloc_csize(mi_theap_t* theap, size_t size) mi_attr_noexcept {
assert(theap!=NULL);
if (size <= MI_SMALL_SIZE_MAX) { return mi_theap_wmalloc_small(theap,mi_wsize_from_size(size)); } else { return mi_theap_malloc(theap,size); }
}
static inline mi_decl_restrict void* mi_theap_zalloc_csize(mi_theap_t* theap, size_t size) mi_attr_noexcept {
assert(theap!=NULL);
if (size <= MI_SMALL_SIZE_MAX) { return mi_theap_wzalloc_small(theap,mi_wsize_from_size(size)); } else { return mi_theap_zalloc(theap,size); }
}

static inline void mi_free_csize(void* p, size_t size) mi_attr_noexcept {
if (size <= MI_SMALL_SIZE_MAX) { mi_free_small(p); } else { mi_free(p); }
}
static inline void mi_free_csize_nonnull(void* p, size_t size) mi_attr_noexcept {
assert(p!=NULL);
if (size <= MI_SMALL_SIZE_MAX) { mi_free_small_nonnull(p); } else { mi_free(p); }
}
static inline void mi_free_csize_aligned(void* p, size_t size, size_t aligned) mi_attr_noexcept {
if (aligned <= size && size <= MI_SMALL_SIZE_MAX) { mi_free_small(p); } else { mi_free(p); }
}
static inline void mi_free_csize_aligned_nonnull(void* p, size_t size, size_t aligned) mi_attr_noexcept {
assert(p!=NULL);
if (aligned <= size && size <= MI_SMALL_SIZE_MAX) { mi_free_small_nonnull(p); } else { mi_free(p); }
}

// ------------------------------------------------------
// C++ standard library allocator interface.
// ------------------------------------------------------

#ifdef __cplusplus
}
#endif
Expand Down
15 changes: 12 additions & 3 deletions include/mimalloc/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -654,6 +654,7 @@ extern mi_decl_hidden mi_theap_t _mi_theap_empty_wrong; // read-only empty theap


static inline mi_heap_t* _mi_theap_heap_peek(const mi_theap_t* theap) {
mi_assert_internal(theap!=NULL);
return mi_atomic_load_ptr_relaxed(mi_heap_t,&theap->heap);
}

Expand Down Expand Up @@ -1154,13 +1155,20 @@ static inline bool _mi_is_process_heap_main(const mi_heap_t* heap) {

// Thread free flag helpers
static inline mi_block_t* mi_tf_block(mi_thread_free_t tf) {
return (mi_block_t*)(tf & ~1);
return (mi_block_t*)(tf & ~1);
}

static inline bool mi_tf_is_owned(mi_thread_free_t tf) {
return ((tf & 1) == 1);
}

static inline mi_thread_free_t mi_tf_create(mi_block_t* block, bool owned) {
return (mi_thread_free_t)((uintptr_t)block | (owned ? 1 : 0));
const uintptr_t base = (uintptr_t)block | (owned ? 1 : 0);
return (mi_thread_free_t)base;
}

static inline mi_thread_free_t mi_tf_set_owned(mi_thread_free_t tf, bool owned) {
return mi_tf_create(mi_tf_block(tf), owned);
}

// Thread free access
Expand Down Expand Up @@ -1515,8 +1523,9 @@ static mi_decl_forceinline void* _mi_memzero_block(mi_block_t* dst, size_t bsize

// fast memzero for small sizes based on overlapping writes (and assuming non-zero size_t-multiple size, and size_t aligned)
// assumes constant memset(p,0,N) gets optimized to fast simd stores by the compiler
// note: disabled on riscv for now as a constant memset is not always replaced correctly by current compilers.
// (compile with -DMI_USE_MEMZERO16X=0 to disable this)
#if !defined(MI_USE_MEMZERO16X) || (MI_USE_MEMZERO16X != 0) // 16x MI_SIZE_SIZE (128 bytes on 64-bit)
#if (!defined(MI_USE_MEMZERO16X) && !MI_ARCH_RISCV) || (MI_USE_MEMZERO16X != 0) // 16x MI_SIZE_SIZE (128 bytes on 64-bit)
if mi_unlikely(bsize < 2*MI_SIZE_SIZE) { // bsize < 16 (8)
*((size_t*)dst) = 0;
return dst;
Expand Down
7 changes: 7 additions & 0 deletions include/mimalloc/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,13 @@ typedef struct mi_page_s {
#define MI_MAX_SINGLETON_BIN MI_BIN_HUGE
#endif

// The small object max size must be larger than twice the small size max minus one,
// such that any aligned allocation with `alignment <= size <= MI_SMALL_SIZE_MAX` will
// be allocated in a small page (so `mi_free_csize` can delegate correctly to `mi_free_small`.
#if MI_SMALL_MAX_OBJ_SIZE <= (2*(MI_SMALL_WSIZE_MAX * MI_SIZE_SIZE)-1)
#error "mimalloc internal: the small object max size is too small"
#endif

// ------------------------------------------------------
// Page kinds
// ------------------------------------------------------
Expand Down
13 changes: 8 additions & 5 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ is a general purpose allocator with excellent [performance](#performance) charac
Initially developed by Daan Leijen for the runtime systems of the
[Koka](https://koka-lang.github.io) and [Lean](https://github.com/leanprover/lean) languages.

Latest release : `v3.5.2` (2026-09-12) recommended.
Latest release : `v3.5.3` (2026-09-16) recommended.
Latest v2 release: `v2.5.2` (2026-09-12) stable, legacy.
Latest v1 release: `v1.15.2` (2026-09-12) legacy.

Expand Down Expand Up @@ -86,10 +86,12 @@ New development is mostly on v3, while v1 and v2 are maintained with security an
(release tags: `v3.x`, development branch `dev3`).
- __v2__: stable legacy mimalloc version. Uses thread-local segments to reduce fragmentation. (release tags: `v2.x`, development branch `dev2` and `main`)
- __v1__: legacy version: initial design of mimalloc (release tags: `v1.x`, development branch `dev`).
__Send PR's against this version if possible.__
__Send PR's against this version if possible (and otherwise `dev3`).__

### Releases

* 2026-09-16, `v3.5.3`: (v3) critical bug fix (where the first new on a thread could
fail on some platforms #1398). Fix bug with `mi_free_size` on overaligned small allocations (#1400).
* 2026-09-12, `v3.5.2`, `v2.5.2`, `v1.15.2`: (v3) Reduced cache contention, improved `mi_malloc_csize`,
improved zero'ing of small blocks, `mi_wmalloc` variants for runtime systems, always enable detailed
statistics. Experimental support for profiling hooks (`mimalloc-profile.h`).
Expand Down Expand Up @@ -600,14 +602,15 @@ In the source code:
- Use `mi_free_small` when the pointer was returned from `mi_malloc_small` (and guaranteed to have a
size of less than `MI_SMALL_SIZE_MAX`). Use `mi_free_small_nonnull` when the pointer is guaranteed to be not `NULL` as well.

For run-time systems and compilers (like Koka, Lean, etc.), we can do slightly better still.
For run-time systems and compilers (like Koka, Lean, Rust (?) etc.), we can do slightly better still.

- If the allocation size is statically known, use `mi_malloc_csize` and `mi_free_csize` etc. when possible.
(or directly `mi_malloc_small`/`mi_free_small`).

- If the runtime already carries thread local state, it may be faster to get the default `theap` for each thread
up-front (`mi_theap_get_default()`) and use the very fast `mi_theap_malloc(_small)` etc. passing the theap
pointer directly. This avoids having mimalloc look up the thread local pointer all the time. Whether this is
up-front (`mi_theap_get_default()`) and use the bestest `mi_theap_malloc(_small)` etc. passing the theap pointer directly.
This avoids having mimalloc look up the thread local pointer all the time and
skips a theap `NULL` check. Whether this is
faster depends a bit on the OS implementation of thread local variables.


Expand Down
Loading
Loading