Path: blob/main/system/lib/mimalloc/include/mimalloc.h
6175 views
/* ----------------------------------------------------------------------------1Copyright (c) 2018-2023, Microsoft Research, Daan Leijen2This is free software; you can redistribute it and/or modify it under the3terms of the MIT license. A copy of the license can be found in the file4"LICENSE" at the root of this distribution.5-----------------------------------------------------------------------------*/6#pragma once7#ifndef MIMALLOC_H8#define MIMALLOC_H910#define MI_MALLOC_VERSION 217 // major + 2 digits minor1112// ------------------------------------------------------13// Compiler specific attributes14// ------------------------------------------------------1516#ifdef __cplusplus17#if (__cplusplus >= 201103L) || (_MSC_VER > 1900) // C++1118#define mi_attr_noexcept noexcept19#else20#define mi_attr_noexcept throw()21#endif22#else23#define mi_attr_noexcept24#endif2526#if defined(__cplusplus) && (__cplusplus >= 201703)27#define mi_decl_nodiscard [[nodiscard]]28#elif (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__) // includes clang, icc, and clang-cl29#define mi_decl_nodiscard __attribute__((warn_unused_result))30#elif defined(_HAS_NODISCARD)31#define mi_decl_nodiscard _NODISCARD32#elif (_MSC_VER >= 1700)33#define mi_decl_nodiscard _Check_return_34#else35#define mi_decl_nodiscard36#endif3738#if defined(_MSC_VER) || defined(__MINGW32__)39#if !defined(MI_SHARED_LIB)40#define mi_decl_export41#elif defined(MI_SHARED_LIB_EXPORT)42#define mi_decl_export __declspec(dllexport)43#else44#define mi_decl_export __declspec(dllimport)45#endif46#if defined(__MINGW32__)47#define mi_decl_restrict48#define mi_attr_malloc __attribute__((malloc))49#else50#if (_MSC_VER >= 1900) && !defined(__EDG__)51#define mi_decl_restrict __declspec(allocator) __declspec(restrict)52#else53#define mi_decl_restrict __declspec(restrict)54#endif55#define mi_attr_malloc56#endif57#define mi_cdecl __cdecl58#define mi_attr_alloc_size(s)59#define mi_attr_alloc_size2(s1,s2)60#define mi_attr_alloc_align(p)61#elif defined(__GNUC__) // includes clang and icc62#if defined(MI_SHARED_LIB) && defined(MI_SHARED_LIB_EXPORT)63#define mi_decl_export __attribute__((visibility("default")))64#else65#define mi_decl_export66#endif67#define mi_cdecl // leads to warnings... __attribute__((cdecl))68#define mi_decl_restrict69#define mi_attr_malloc __attribute__((malloc))70#if (defined(__clang_major__) && (__clang_major__ < 4)) || (__GNUC__ < 5)71#define mi_attr_alloc_size(s)72#define mi_attr_alloc_size2(s1,s2)73#define mi_attr_alloc_align(p)74#elif defined(__INTEL_COMPILER)75#define mi_attr_alloc_size(s) __attribute__((alloc_size(s)))76#define mi_attr_alloc_size2(s1,s2) __attribute__((alloc_size(s1,s2)))77#define mi_attr_alloc_align(p)78#else79#define mi_attr_alloc_size(s) __attribute__((alloc_size(s)))80#define mi_attr_alloc_size2(s1,s2) __attribute__((alloc_size(s1,s2)))81#define mi_attr_alloc_align(p) __attribute__((alloc_align(p)))82#endif83#else84#define mi_cdecl85#define mi_decl_export86#define mi_decl_restrict87#define mi_attr_malloc88#define mi_attr_alloc_size(s)89#define mi_attr_alloc_size2(s1,s2)90#define mi_attr_alloc_align(p)91#endif9293// ------------------------------------------------------94// Includes95// ------------------------------------------------------9697#include <stddef.h> // size_t98#include <stdbool.h> // bool99#include <stdint.h> // INTPTR_MAX100101#ifdef __cplusplus102extern "C" {103#endif104105// ------------------------------------------------------106// Standard malloc interface107// ------------------------------------------------------108109mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_malloc(size_t size) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(1);110mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_calloc(size_t count, size_t size) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size2(1,2);111mi_decl_nodiscard mi_decl_export void* mi_realloc(void* p, size_t newsize) mi_attr_noexcept mi_attr_alloc_size(2);112mi_decl_export void* mi_expand(void* p, size_t newsize) mi_attr_noexcept mi_attr_alloc_size(2);113114mi_decl_export void mi_free(void* p) mi_attr_noexcept;115mi_decl_nodiscard mi_decl_export mi_decl_restrict char* mi_strdup(const char* s) mi_attr_noexcept mi_attr_malloc;116mi_decl_nodiscard mi_decl_export mi_decl_restrict char* mi_strndup(const char* s, size_t n) mi_attr_noexcept mi_attr_malloc;117mi_decl_nodiscard mi_decl_export mi_decl_restrict char* mi_realpath(const char* fname, char* resolved_name) mi_attr_noexcept mi_attr_malloc;118119// ------------------------------------------------------120// Extended functionality121// ------------------------------------------------------122#define MI_SMALL_WSIZE_MAX (128)123#define MI_SMALL_SIZE_MAX (MI_SMALL_WSIZE_MAX*sizeof(void*))124125mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_malloc_small(size_t size) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(1);126mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_zalloc_small(size_t size) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(1);127mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_zalloc(size_t size) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(1);128129mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_mallocn(size_t count, size_t size) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size2(1,2);130mi_decl_nodiscard mi_decl_export void* mi_reallocn(void* p, size_t count, size_t size) mi_attr_noexcept mi_attr_alloc_size2(2,3);131mi_decl_nodiscard mi_decl_export void* mi_reallocf(void* p, size_t newsize) mi_attr_noexcept mi_attr_alloc_size(2);132133mi_decl_nodiscard mi_decl_export size_t mi_usable_size(const void* p) mi_attr_noexcept;134mi_decl_nodiscard mi_decl_export size_t mi_good_size(size_t size) mi_attr_noexcept;135136137// ------------------------------------------------------138// Internals139// ------------------------------------------------------140141typedef void (mi_cdecl mi_deferred_free_fun)(bool force, unsigned long long heartbeat, void* arg);142mi_decl_export void mi_register_deferred_free(mi_deferred_free_fun* deferred_free, void* arg) mi_attr_noexcept;143144typedef void (mi_cdecl mi_output_fun)(const char* msg, void* arg);145mi_decl_export void mi_register_output(mi_output_fun* out, void* arg) mi_attr_noexcept;146147typedef void (mi_cdecl mi_error_fun)(int err, void* arg);148mi_decl_export void mi_register_error(mi_error_fun* fun, void* arg);149150mi_decl_export void mi_collect(bool force) mi_attr_noexcept;151mi_decl_export int mi_version(void) mi_attr_noexcept;152mi_decl_export void mi_stats_reset(void) mi_attr_noexcept;153mi_decl_export void mi_stats_merge(void) mi_attr_noexcept;154mi_decl_export void mi_stats_print(void* out) mi_attr_noexcept; // backward compatibility: `out` is ignored and should be NULL155mi_decl_export void mi_stats_print_out(mi_output_fun* out, void* arg) mi_attr_noexcept;156157mi_decl_export void mi_process_init(void) mi_attr_noexcept;158mi_decl_export void mi_thread_init(void) mi_attr_noexcept;159mi_decl_export void mi_thread_done(void) mi_attr_noexcept;160mi_decl_export void mi_thread_stats_print_out(mi_output_fun* out, void* arg) mi_attr_noexcept;161162mi_decl_export void mi_process_info(size_t* elapsed_msecs, size_t* user_msecs, size_t* system_msecs,163size_t* current_rss, size_t* peak_rss,164size_t* current_commit, size_t* peak_commit, size_t* page_faults) mi_attr_noexcept;165166// -------------------------------------------------------------------------------------167// Aligned allocation168// Note that `alignment` always follows `size` for consistency with unaligned169// allocation, but unfortunately this differs from `posix_memalign` and `aligned_alloc`.170// -------------------------------------------------------------------------------------171172mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_malloc_aligned(size_t size, size_t alignment) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(1) mi_attr_alloc_align(2);173mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_malloc_aligned_at(size_t size, size_t alignment, size_t offset) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(1);174mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_zalloc_aligned(size_t size, size_t alignment) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(1) mi_attr_alloc_align(2);175mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_zalloc_aligned_at(size_t size, size_t alignment, size_t offset) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(1);176mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_calloc_aligned(size_t count, size_t size, size_t alignment) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size2(1,2) mi_attr_alloc_align(3);177mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_calloc_aligned_at(size_t count, size_t size, size_t alignment, size_t offset) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size2(1,2);178mi_decl_nodiscard mi_decl_export void* mi_realloc_aligned(void* p, size_t newsize, size_t alignment) mi_attr_noexcept mi_attr_alloc_size(2) mi_attr_alloc_align(3);179mi_decl_nodiscard mi_decl_export void* mi_realloc_aligned_at(void* p, size_t newsize, size_t alignment, size_t offset) mi_attr_noexcept mi_attr_alloc_size(2);180181182// -------------------------------------------------------------------------------------183// Heaps: first-class, but can only allocate from the same thread that created it.184// -------------------------------------------------------------------------------------185186struct mi_heap_s;187typedef struct mi_heap_s mi_heap_t;188189mi_decl_nodiscard mi_decl_export mi_heap_t* mi_heap_new(void);190mi_decl_export void mi_heap_delete(mi_heap_t* heap);191mi_decl_export void mi_heap_destroy(mi_heap_t* heap);192mi_decl_export mi_heap_t* mi_heap_set_default(mi_heap_t* heap);193mi_decl_export mi_heap_t* mi_heap_get_default(void);194mi_decl_export mi_heap_t* mi_heap_get_backing(void);195mi_decl_export void mi_heap_collect(mi_heap_t* heap, bool force) mi_attr_noexcept;196197mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_heap_malloc(mi_heap_t* heap, size_t size) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(2);198mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_heap_zalloc(mi_heap_t* heap, size_t size) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(2);199mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_heap_calloc(mi_heap_t* heap, size_t count, size_t size) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size2(2, 3);200mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_heap_mallocn(mi_heap_t* heap, size_t count, size_t size) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size2(2, 3);201mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_heap_malloc_small(mi_heap_t* heap, size_t size) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(2);202203mi_decl_nodiscard mi_decl_export void* mi_heap_realloc(mi_heap_t* heap, void* p, size_t newsize) mi_attr_noexcept mi_attr_alloc_size(3);204mi_decl_nodiscard mi_decl_export void* mi_heap_reallocn(mi_heap_t* heap, void* p, size_t count, size_t size) mi_attr_noexcept mi_attr_alloc_size2(3,4);205mi_decl_nodiscard mi_decl_export void* mi_heap_reallocf(mi_heap_t* heap, void* p, size_t newsize) mi_attr_noexcept mi_attr_alloc_size(3);206207mi_decl_nodiscard mi_decl_export mi_decl_restrict char* mi_heap_strdup(mi_heap_t* heap, const char* s) mi_attr_noexcept mi_attr_malloc;208mi_decl_nodiscard mi_decl_export mi_decl_restrict char* mi_heap_strndup(mi_heap_t* heap, const char* s, size_t n) mi_attr_noexcept mi_attr_malloc;209mi_decl_nodiscard mi_decl_export mi_decl_restrict char* mi_heap_realpath(mi_heap_t* heap, const char* fname, char* resolved_name) mi_attr_noexcept mi_attr_malloc;210211mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_heap_malloc_aligned(mi_heap_t* heap, size_t size, size_t alignment) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(2) mi_attr_alloc_align(3);212mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_heap_malloc_aligned_at(mi_heap_t* heap, size_t size, size_t alignment, size_t offset) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(2);213mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_heap_zalloc_aligned(mi_heap_t* heap, size_t size, size_t alignment) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(2) mi_attr_alloc_align(3);214mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_heap_zalloc_aligned_at(mi_heap_t* heap, size_t size, size_t alignment, size_t offset) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(2);215mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_heap_calloc_aligned(mi_heap_t* heap, size_t count, size_t size, size_t alignment) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size2(2, 3) mi_attr_alloc_align(4);216mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_heap_calloc_aligned_at(mi_heap_t* heap, size_t count, size_t size, size_t alignment, size_t offset) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size2(2, 3);217mi_decl_nodiscard mi_decl_export void* mi_heap_realloc_aligned(mi_heap_t* heap, void* p, size_t newsize, size_t alignment) mi_attr_noexcept mi_attr_alloc_size(3) mi_attr_alloc_align(4);218mi_decl_nodiscard mi_decl_export void* mi_heap_realloc_aligned_at(mi_heap_t* heap, void* p, size_t newsize, size_t alignment, size_t offset) mi_attr_noexcept mi_attr_alloc_size(3);219220221// --------------------------------------------------------------------------------222// Zero initialized re-allocation.223// Only valid on memory that was originally allocated with zero initialization too.224// e.g. `mi_calloc`, `mi_zalloc`, `mi_zalloc_aligned` etc.225// see <https://github.com/microsoft/mimalloc/issues/63#issuecomment-508272992>226// --------------------------------------------------------------------------------227228mi_decl_nodiscard mi_decl_export void* mi_rezalloc(void* p, size_t newsize) mi_attr_noexcept mi_attr_alloc_size(2);229mi_decl_nodiscard mi_decl_export void* mi_recalloc(void* p, size_t newcount, size_t size) mi_attr_noexcept mi_attr_alloc_size2(2,3);230231mi_decl_nodiscard mi_decl_export void* mi_rezalloc_aligned(void* p, size_t newsize, size_t alignment) mi_attr_noexcept mi_attr_alloc_size(2) mi_attr_alloc_align(3);232mi_decl_nodiscard mi_decl_export void* mi_rezalloc_aligned_at(void* p, size_t newsize, size_t alignment, size_t offset) mi_attr_noexcept mi_attr_alloc_size(2);233mi_decl_nodiscard mi_decl_export void* mi_recalloc_aligned(void* p, size_t newcount, size_t size, size_t alignment) mi_attr_noexcept mi_attr_alloc_size2(2,3) mi_attr_alloc_align(4);234mi_decl_nodiscard mi_decl_export void* mi_recalloc_aligned_at(void* p, size_t newcount, size_t size, size_t alignment, size_t offset) mi_attr_noexcept mi_attr_alloc_size2(2,3);235236mi_decl_nodiscard mi_decl_export void* mi_heap_rezalloc(mi_heap_t* heap, void* p, size_t newsize) mi_attr_noexcept mi_attr_alloc_size(3);237mi_decl_nodiscard mi_decl_export void* mi_heap_recalloc(mi_heap_t* heap, void* p, size_t newcount, size_t size) mi_attr_noexcept mi_attr_alloc_size2(3,4);238239mi_decl_nodiscard mi_decl_export void* mi_heap_rezalloc_aligned(mi_heap_t* heap, void* p, size_t newsize, size_t alignment) mi_attr_noexcept mi_attr_alloc_size(3) mi_attr_alloc_align(4);240mi_decl_nodiscard mi_decl_export void* mi_heap_rezalloc_aligned_at(mi_heap_t* heap, void* p, size_t newsize, size_t alignment, size_t offset) mi_attr_noexcept mi_attr_alloc_size(3);241mi_decl_nodiscard mi_decl_export void* mi_heap_recalloc_aligned(mi_heap_t* heap, void* p, size_t newcount, size_t size, size_t alignment) mi_attr_noexcept mi_attr_alloc_size2(3,4) mi_attr_alloc_align(5);242mi_decl_nodiscard mi_decl_export void* mi_heap_recalloc_aligned_at(mi_heap_t* heap, void* p, size_t newcount, size_t size, size_t alignment, size_t offset) mi_attr_noexcept mi_attr_alloc_size2(3,4);243244245// ------------------------------------------------------246// Analysis247// ------------------------------------------------------248249mi_decl_export bool mi_heap_contains_block(mi_heap_t* heap, const void* p);250mi_decl_export bool mi_heap_check_owned(mi_heap_t* heap, const void* p);251mi_decl_export bool mi_check_owned(const void* p);252253// An area of heap space contains blocks of a single size.254typedef struct mi_heap_area_s {255void* blocks; // start of the area containing heap blocks256size_t reserved; // bytes reserved for this area (virtual)257size_t committed; // current available bytes for this area258size_t used; // number of allocated blocks259size_t block_size; // size in bytes of each block260size_t full_block_size; // size in bytes of a full block including padding and metadata.261} mi_heap_area_t;262263typedef bool (mi_cdecl mi_block_visit_fun)(const mi_heap_t* heap, const mi_heap_area_t* area, void* block, size_t block_size, void* arg);264265mi_decl_export bool mi_heap_visit_blocks(const mi_heap_t* heap, bool visit_all_blocks, mi_block_visit_fun* visitor, void* arg);266267// Experimental268mi_decl_nodiscard mi_decl_export bool mi_is_in_heap_region(const void* p) mi_attr_noexcept;269mi_decl_nodiscard mi_decl_export bool mi_is_redirected(void) mi_attr_noexcept;270271mi_decl_export int mi_reserve_huge_os_pages_interleave(size_t pages, size_t numa_nodes, size_t timeout_msecs) mi_attr_noexcept;272mi_decl_export int mi_reserve_huge_os_pages_at(size_t pages, int numa_node, size_t timeout_msecs) mi_attr_noexcept;273274mi_decl_export int mi_reserve_os_memory(size_t size, bool commit, bool allow_large) mi_attr_noexcept;275mi_decl_export bool mi_manage_os_memory(void* start, size_t size, bool is_committed, bool is_large, bool is_zero, int numa_node) mi_attr_noexcept;276277mi_decl_export void mi_debug_show_arenas(bool show_inuse, bool show_abandoned, bool show_purge) mi_attr_noexcept;278279// Experimental: heaps associated with specific memory arena's280typedef int mi_arena_id_t;281mi_decl_export void* mi_arena_area(mi_arena_id_t arena_id, size_t* size);282mi_decl_export int mi_reserve_huge_os_pages_at_ex(size_t pages, int numa_node, size_t timeout_msecs, bool exclusive, mi_arena_id_t* arena_id) mi_attr_noexcept;283mi_decl_export int mi_reserve_os_memory_ex(size_t size, bool commit, bool allow_large, bool exclusive, mi_arena_id_t* arena_id) mi_attr_noexcept;284mi_decl_export bool mi_manage_os_memory_ex(void* start, size_t size, bool is_committed, bool is_large, bool is_zero, int numa_node, bool exclusive, mi_arena_id_t* arena_id) mi_attr_noexcept;285286#if MI_MALLOC_VERSION >= 182287// Create a heap that only allocates in the specified arena288mi_decl_nodiscard mi_decl_export mi_heap_t* mi_heap_new_in_arena(mi_arena_id_t arena_id);289#endif290291// deprecated292mi_decl_export int mi_reserve_huge_os_pages(size_t pages, double max_secs, size_t* pages_reserved) mi_attr_noexcept;293294295// ------------------------------------------------------296// Convenience297// ------------------------------------------------------298299#define mi_malloc_tp(tp) ((tp*)mi_malloc(sizeof(tp)))300#define mi_zalloc_tp(tp) ((tp*)mi_zalloc(sizeof(tp)))301#define mi_calloc_tp(tp,n) ((tp*)mi_calloc(n,sizeof(tp)))302#define mi_mallocn_tp(tp,n) ((tp*)mi_mallocn(n,sizeof(tp)))303#define mi_reallocn_tp(p,tp,n) ((tp*)mi_reallocn(p,n,sizeof(tp)))304#define mi_recalloc_tp(p,tp,n) ((tp*)mi_recalloc(p,n,sizeof(tp)))305306#define mi_heap_malloc_tp(hp,tp) ((tp*)mi_heap_malloc(hp,sizeof(tp)))307#define mi_heap_zalloc_tp(hp,tp) ((tp*)mi_heap_zalloc(hp,sizeof(tp)))308#define mi_heap_calloc_tp(hp,tp,n) ((tp*)mi_heap_calloc(hp,n,sizeof(tp)))309#define mi_heap_mallocn_tp(hp,tp,n) ((tp*)mi_heap_mallocn(hp,n,sizeof(tp)))310#define mi_heap_reallocn_tp(hp,p,tp,n) ((tp*)mi_heap_reallocn(hp,p,n,sizeof(tp)))311#define mi_heap_recalloc_tp(hp,p,tp,n) ((tp*)mi_heap_recalloc(hp,p,n,sizeof(tp)))312313314// ------------------------------------------------------315// Options316// ------------------------------------------------------317318typedef enum mi_option_e {319// stable options320mi_option_show_errors, // print error messages321mi_option_show_stats, // print statistics on termination322mi_option_verbose, // print verbose messages323// advanced options324mi_option_eager_commit, // eager commit segments? (after `eager_commit_delay` segments) (=1)325mi_option_arena_eager_commit, // eager commit arenas? Use 2 to enable just on overcommit systems (=2)326mi_option_purge_decommits, // should a memory purge decommit? (=1). Set to 0 to use memory reset on a purge (instead of decommit)327mi_option_allow_large_os_pages, // allow large (2 or 4 MiB) OS pages, implies eager commit. If false, also disables THP for the process.328mi_option_reserve_huge_os_pages, // reserve N huge OS pages (1GiB pages) at startup329mi_option_reserve_huge_os_pages_at, // reserve huge OS pages at a specific NUMA node330mi_option_reserve_os_memory, // reserve specified amount of OS memory in an arena at startup (internally, this value is in KiB; use `mi_option_get_size`)331mi_option_deprecated_segment_cache,332mi_option_deprecated_page_reset,333mi_option_abandoned_page_purge, // immediately purge delayed purges on thread termination334mi_option_deprecated_segment_reset,335mi_option_eager_commit_delay, // the first N segments per thread are not eagerly committed (but per page in the segment on demand)336mi_option_purge_delay, // memory purging is delayed by N milli seconds; use 0 for immediate purging or -1 for no purging at all. (=10)337mi_option_use_numa_nodes, // 0 = use all available numa nodes, otherwise use at most N nodes.338mi_option_disallow_os_alloc, // 1 = do not use OS memory for allocation (but only programmatically reserved arenas)339mi_option_os_tag, // tag used for OS logging (macOS only for now) (=100)340mi_option_max_errors, // issue at most N error messages341mi_option_max_warnings, // issue at most N warning messages342mi_option_max_segment_reclaim, // max. percentage of the abandoned segments can be reclaimed per try (=10%)343mi_option_destroy_on_exit, // if set, release all memory on exit; sometimes used for dynamic unloading but can be unsafe344mi_option_arena_reserve, // initial memory size for arena reservation (= 1 GiB on 64-bit) (internally, this value is in KiB; use `mi_option_get_size`)345mi_option_arena_purge_mult, // multiplier for `purge_delay` for the purging delay for arenas (=10)346mi_option_purge_extend_delay,347mi_option_abandoned_reclaim_on_free, // allow to reclaim an abandoned segment on a free (=1)348mi_option_disallow_arena_alloc, // 1 = do not use arena's for allocation (except if using specific arena id's)349mi_option_retry_on_oom, // retry on out-of-memory for N milli seconds (=400), set to 0 to disable retries. (only on windows)350_mi_option_last,351// legacy option names352mi_option_large_os_pages = mi_option_allow_large_os_pages,353mi_option_eager_region_commit = mi_option_arena_eager_commit,354mi_option_reset_decommits = mi_option_purge_decommits,355mi_option_reset_delay = mi_option_purge_delay,356mi_option_abandoned_page_reset = mi_option_abandoned_page_purge,357mi_option_limit_os_alloc = mi_option_disallow_os_alloc358} mi_option_t;359360361mi_decl_nodiscard mi_decl_export bool mi_option_is_enabled(mi_option_t option);362mi_decl_export void mi_option_enable(mi_option_t option);363mi_decl_export void mi_option_disable(mi_option_t option);364mi_decl_export void mi_option_set_enabled(mi_option_t option, bool enable);365mi_decl_export void mi_option_set_enabled_default(mi_option_t option, bool enable);366367mi_decl_nodiscard mi_decl_export long mi_option_get(mi_option_t option);368mi_decl_nodiscard mi_decl_export long mi_option_get_clamp(mi_option_t option, long min, long max);369mi_decl_nodiscard mi_decl_export size_t mi_option_get_size(mi_option_t option);370mi_decl_export void mi_option_set(mi_option_t option, long value);371mi_decl_export void mi_option_set_default(mi_option_t option, long value);372373374// -------------------------------------------------------------------------------------------------------375// "mi" prefixed implementations of various posix, Unix, Windows, and C++ allocation functions.376// (This can be convenient when providing overrides of these functions as done in `mimalloc-override.h`.)377// note: we use `mi_cfree` as "checked free" and it checks if the pointer is in our heap before free-ing.378// -------------------------------------------------------------------------------------------------------379380mi_decl_export void mi_cfree(void* p) mi_attr_noexcept;381mi_decl_export void* mi__expand(void* p, size_t newsize) mi_attr_noexcept;382mi_decl_nodiscard mi_decl_export size_t mi_malloc_size(const void* p) mi_attr_noexcept;383mi_decl_nodiscard mi_decl_export size_t mi_malloc_good_size(size_t size) mi_attr_noexcept;384mi_decl_nodiscard mi_decl_export size_t mi_malloc_usable_size(const void *p) mi_attr_noexcept;385386mi_decl_export int mi_posix_memalign(void** p, size_t alignment, size_t size) mi_attr_noexcept;387mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_memalign(size_t alignment, size_t size) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(2) mi_attr_alloc_align(1);388mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_valloc(size_t size) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(1);389mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_pvalloc(size_t size) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(1);390mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_aligned_alloc(size_t alignment, size_t size) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(2) mi_attr_alloc_align(1);391392mi_decl_nodiscard mi_decl_export void* mi_reallocarray(void* p, size_t count, size_t size) mi_attr_noexcept mi_attr_alloc_size2(2,3);393mi_decl_nodiscard mi_decl_export int mi_reallocarr(void* p, size_t count, size_t size) mi_attr_noexcept;394mi_decl_nodiscard mi_decl_export void* mi_aligned_recalloc(void* p, size_t newcount, size_t size, size_t alignment) mi_attr_noexcept;395mi_decl_nodiscard mi_decl_export void* mi_aligned_offset_recalloc(void* p, size_t newcount, size_t size, size_t alignment, size_t offset) mi_attr_noexcept;396397mi_decl_nodiscard mi_decl_export mi_decl_restrict unsigned short* mi_wcsdup(const unsigned short* s) mi_attr_noexcept mi_attr_malloc;398mi_decl_nodiscard mi_decl_export mi_decl_restrict unsigned char* mi_mbsdup(const unsigned char* s) mi_attr_noexcept mi_attr_malloc;399mi_decl_export int mi_dupenv_s(char** buf, size_t* size, const char* name) mi_attr_noexcept;400mi_decl_export int mi_wdupenv_s(unsigned short** buf, size_t* size, const unsigned short* name) mi_attr_noexcept;401402mi_decl_export void mi_free_size(void* p, size_t size) mi_attr_noexcept;403mi_decl_export void mi_free_size_aligned(void* p, size_t size, size_t alignment) mi_attr_noexcept;404mi_decl_export void mi_free_aligned(void* p, size_t alignment) mi_attr_noexcept;405406// The `mi_new` wrappers implement C++ semantics on out-of-memory instead of directly returning `NULL`.407// (and call `std::get_new_handler` and potentially raise a `std::bad_alloc` exception).408mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_new(size_t size) mi_attr_malloc mi_attr_alloc_size(1);409mi_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);410mi_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);411mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_new_aligned_nothrow(size_t size, size_t alignment) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(1) mi_attr_alloc_align(2);412mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_new_n(size_t count, size_t size) mi_attr_malloc mi_attr_alloc_size2(1, 2);413mi_decl_nodiscard mi_decl_export void* mi_new_realloc(void* p, size_t newsize) mi_attr_alloc_size(2);414mi_decl_nodiscard mi_decl_export void* mi_new_reallocn(void* p, size_t newcount, size_t size) mi_attr_alloc_size2(2, 3);415416mi_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);417mi_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);418419#ifdef __cplusplus420}421#endif422423// ---------------------------------------------------------------------------------------------424// Implement the C++ std::allocator interface for use in STL containers.425// (note: see `mimalloc-new-delete.h` for overriding the new/delete operators globally)426// ---------------------------------------------------------------------------------------------427#ifdef __cplusplus428429#include <cstddef> // std::size_t430#include <cstdint> // PTRDIFF_MAX431#if (__cplusplus >= 201103L) || (_MSC_VER > 1900) // C++11432#include <type_traits> // std::true_type433#include <utility> // std::forward434#endif435436template<class T> struct _mi_stl_allocator_common {437typedef T value_type;438typedef std::size_t size_type;439typedef std::ptrdiff_t difference_type;440typedef value_type& reference;441typedef value_type const& const_reference;442typedef value_type* pointer;443typedef value_type const* const_pointer;444445#if ((__cplusplus >= 201103L) || (_MSC_VER > 1900)) // C++11446using propagate_on_container_copy_assignment = std::true_type;447using propagate_on_container_move_assignment = std::true_type;448using propagate_on_container_swap = std::true_type;449template <class U, class ...Args> void construct(U* p, Args&& ...args) { ::new(p) U(std::forward<Args>(args)...); }450template <class U> void destroy(U* p) mi_attr_noexcept { p->~U(); }451#else452void construct(pointer p, value_type const& val) { ::new(p) value_type(val); }453void destroy(pointer p) { p->~value_type(); }454#endif455456size_type max_size() const mi_attr_noexcept { return (PTRDIFF_MAX/sizeof(value_type)); }457pointer address(reference x) const { return &x; }458const_pointer address(const_reference x) const { return &x; }459};460461template<class T> struct mi_stl_allocator : public _mi_stl_allocator_common<T> {462using typename _mi_stl_allocator_common<T>::size_type;463using typename _mi_stl_allocator_common<T>::value_type;464using typename _mi_stl_allocator_common<T>::pointer;465template <class U> struct rebind { typedef mi_stl_allocator<U> other; };466467mi_stl_allocator() mi_attr_noexcept = default;468mi_stl_allocator(const mi_stl_allocator&) mi_attr_noexcept = default;469template<class U> mi_stl_allocator(const mi_stl_allocator<U>&) mi_attr_noexcept { }470mi_stl_allocator select_on_container_copy_construction() const { return *this; }471void deallocate(T* p, size_type) { mi_free(p); }472473#if (__cplusplus >= 201703L) // C++17474mi_decl_nodiscard T* allocate(size_type count) { return static_cast<T*>(mi_new_n(count, sizeof(T))); }475mi_decl_nodiscard T* allocate(size_type count, const void*) { return allocate(count); }476#else477mi_decl_nodiscard pointer allocate(size_type count, const void* = 0) { return static_cast<pointer>(mi_new_n(count, sizeof(value_type))); }478#endif479480#if ((__cplusplus >= 201103L) || (_MSC_VER > 1900)) // C++11481using is_always_equal = std::true_type;482#endif483};484485template<class T1,class T2> bool operator==(const mi_stl_allocator<T1>& , const mi_stl_allocator<T2>& ) mi_attr_noexcept { return true; }486template<class T1,class T2> bool operator!=(const mi_stl_allocator<T1>& , const mi_stl_allocator<T2>& ) mi_attr_noexcept { return false; }487488489#if (__cplusplus >= 201103L) || (_MSC_VER >= 1900) // C++11490#define MI_HAS_HEAP_STL_ALLOCATOR 1491492#include <memory> // std::shared_ptr493494// Common base class for STL allocators in a specific heap495template<class T, bool _mi_destroy> struct _mi_heap_stl_allocator_common : public _mi_stl_allocator_common<T> {496using typename _mi_stl_allocator_common<T>::size_type;497using typename _mi_stl_allocator_common<T>::value_type;498using typename _mi_stl_allocator_common<T>::pointer;499500_mi_heap_stl_allocator_common(mi_heap_t* hp) : heap(hp, [](mi_heap_t*) {}) {} /* will not delete nor destroy the passed in heap */501502#if (__cplusplus >= 201703L) // C++17503mi_decl_nodiscard T* allocate(size_type count) { return static_cast<T*>(mi_heap_alloc_new_n(this->heap.get(), count, sizeof(T))); }504mi_decl_nodiscard T* allocate(size_type count, const void*) { return allocate(count); }505#else506mi_decl_nodiscard pointer allocate(size_type count, const void* = 0) { return static_cast<pointer>(mi_heap_alloc_new_n(this->heap.get(), count, sizeof(value_type))); }507#endif508509#if ((__cplusplus >= 201103L) || (_MSC_VER > 1900)) // C++11510using is_always_equal = std::false_type;511#endif512513void collect(bool force) { mi_heap_collect(this->heap.get(), force); }514template<class U> bool is_equal(const _mi_heap_stl_allocator_common<U, _mi_destroy>& x) const { return (this->heap == x.heap); }515516protected:517std::shared_ptr<mi_heap_t> heap;518template<class U, bool D> friend struct _mi_heap_stl_allocator_common;519520_mi_heap_stl_allocator_common() {521mi_heap_t* hp = mi_heap_new();522this->heap.reset(hp, (_mi_destroy ? &heap_destroy : &heap_delete)); /* calls heap_delete/destroy when the refcount drops to zero */523}524_mi_heap_stl_allocator_common(const _mi_heap_stl_allocator_common& x) mi_attr_noexcept : heap(x.heap) { }525template<class U> _mi_heap_stl_allocator_common(const _mi_heap_stl_allocator_common<U, _mi_destroy>& x) mi_attr_noexcept : heap(x.heap) { }526527private:528static void heap_delete(mi_heap_t* hp) { if (hp != NULL) { mi_heap_delete(hp); } }529static void heap_destroy(mi_heap_t* hp) { if (hp != NULL) { mi_heap_destroy(hp); } }530};531532// STL allocator allocation in a specific heap533template<class T> struct mi_heap_stl_allocator : public _mi_heap_stl_allocator_common<T, false> {534using typename _mi_heap_stl_allocator_common<T, false>::size_type;535mi_heap_stl_allocator() : _mi_heap_stl_allocator_common<T, false>() { } // creates fresh heap that is deleted when the destructor is called536mi_heap_stl_allocator(mi_heap_t* hp) : _mi_heap_stl_allocator_common<T, false>(hp) { } // no delete nor destroy on the passed in heap537template<class U> mi_heap_stl_allocator(const mi_heap_stl_allocator<U>& x) mi_attr_noexcept : _mi_heap_stl_allocator_common<T, false>(x) { }538539mi_heap_stl_allocator select_on_container_copy_construction() const { return *this; }540void deallocate(T* p, size_type) { mi_free(p); }541template<class U> struct rebind { typedef mi_heap_stl_allocator<U> other; };542};543544template<class T1, class T2> bool operator==(const mi_heap_stl_allocator<T1>& x, const mi_heap_stl_allocator<T2>& y) mi_attr_noexcept { return (x.is_equal(y)); }545template<class T1, class T2> bool operator!=(const mi_heap_stl_allocator<T1>& x, const mi_heap_stl_allocator<T2>& y) mi_attr_noexcept { return (!x.is_equal(y)); }546547548// STL allocator allocation in a specific heap, where `free` does nothing and549// the heap is destroyed in one go on destruction -- use with care!550template<class T> struct mi_heap_destroy_stl_allocator : public _mi_heap_stl_allocator_common<T, true> {551using typename _mi_heap_stl_allocator_common<T, true>::size_type;552mi_heap_destroy_stl_allocator() : _mi_heap_stl_allocator_common<T, true>() { } // creates fresh heap that is destroyed when the destructor is called553mi_heap_destroy_stl_allocator(mi_heap_t* hp) : _mi_heap_stl_allocator_common<T, true>(hp) { } // no delete nor destroy on the passed in heap554template<class U> mi_heap_destroy_stl_allocator(const mi_heap_destroy_stl_allocator<U>& x) mi_attr_noexcept : _mi_heap_stl_allocator_common<T, true>(x) { }555556mi_heap_destroy_stl_allocator select_on_container_copy_construction() const { return *this; }557void deallocate(T*, size_type) { /* do nothing as we destroy the heap on destruct. */ }558template<class U> struct rebind { typedef mi_heap_destroy_stl_allocator<U> other; };559};560561template<class T1, class T2> bool operator==(const mi_heap_destroy_stl_allocator<T1>& x, const mi_heap_destroy_stl_allocator<T2>& y) mi_attr_noexcept { return (x.is_equal(y)); }562template<class T1, class T2> bool operator!=(const mi_heap_destroy_stl_allocator<T1>& x, const mi_heap_destroy_stl_allocator<T2>& y) mi_attr_noexcept { return (!x.is_equal(y)); }563564#endif // C++11565566#endif // __cplusplus567568#endif569570571