mi-malloc: Overriding Malloc

| mi-malloc 1.8/2.1 |

Loading...
Searching...
No Matches
Overriding Malloc

Overriding the standard `malloc` (and `new`) can be done either dynamically or statically.

## Dynamic override

This is the recommended way to override the standard malloc interface.

### Dynamic Override on Linux, BSD

On these ELF-based systems we preload the mimalloc shared library so all calls to the standard `malloc` interface are resolved to the mimalloc library.

> env LD_PRELOAD=/usr/lib/libmimalloc.so myprogram

You can set extra environment variables to check that mimalloc is running, like:

> env MIMALLOC_VERBOSE=1 LD_PRELOAD=/usr/lib/libmimalloc.so myprogram

or run with the debug version to get detailed statistics:

> env MIMALLOC_SHOW_STATS=1 LD_PRELOAD=/usr/lib/libmimalloc-debug.so myprogram

### Dynamic Override on MacOS

On macOS we can also preload the mimalloc shared library so all calls to the standard `malloc` interface are resolved to the mimalloc library.

> env DYLD_INSERT_LIBRARIES=/usr/lib/libmimalloc.dylib myprogram

Note that certain security restrictions may apply when doing this from the shell.

### Dynamic Override on Windows

Dynamically overriding on mimalloc on Windows is robust and has the particular advantage to be able to redirect all malloc/free calls that go through the (dynamic) C runtime allocator, including those from other DLL's or libraries. As it intercepts all allocation calls on a low level, it can be used reliably on large programs that include other 3rd party components. There are four requirements to make the overriding work well:

1. Use the C-runtime library as a DLL (using the `/MD` or `/MDd` switch).
2. Link your program explicitly with the `mimalloc.lib` export library for the `mimalloc.dll`. (which must be compiled with `-DMI_OVERRIDE=ON`, which is the default though). To ensure the `mimalloc.dll` is actually loaded at run-time it is easiest to insert some call to the mimalloc API in the `main` function, like `mi_version()` (or use the `/include:mi_version` switch on the linker command, or similarly, `#pragma comment(linker, "/include:mi_version")` in some source file). See the `mimalloc-test-override` project for an example on how to use this.
3. The `mimalloc-redirect.dll` must be put in the same directory as the main `mimalloc.dll` at runtime (as it is a dependency of that DLL). The redirection DLL ensures that all calls to the C runtime malloc API get redirected to mimalloc functions (which reside in `mimalloc.dll`).
4. Ensure the `mimalloc.dll` comes as early as possible in the import list of the final executable (so it can intercept all potential allocations). You can use `minject -l <exe>` to check this if needed.

For best performance on Windows with C++, it is also recommended to also override the `new`/`delete` operations (by including `mimalloc-new-delete.h` a single(!) source file in your project).

The environment variable `MIMALLOC_DISABLE_REDIRECT=1` can be used to disable dynamic overriding at run-time. Use `MIMALLOC_VERBOSE=1` to check if mimalloc was successfully redirected.

For different platforms than x64, you may need a specific [redirection dll](bin). Furthermore, we cannot always re-link an executable or ensure `mimalloc.dll` comes first in the import table. In such cases the [`minject`](bin) tool can be used to patch the executable's import tables.

## Static override

On Unix-like systems, you can also statically link with mimalloc to override the standard malloc interface. The recommended way is to link the final program with the mimalloc single object file (`mimalloc.o`). We use an object file instead of a library file as linkers give preference to that over archives to resolve symbols. To ensure that the standard malloc interface resolves to the mimalloc library, link it as the first object file. For example:

> gcc -o myprogram mimalloc.o myfile1.c ...

Another way to override statically that works on all platforms, is to link statically to mimalloc (as shown in the introduction) and include a header file in each source file that re-defines `malloc` etc. to `mi_malloc`. This is provided by `mimalloc-override.h`. This only works reliably though if all sources are under your control or otherwise mixing of pointers from different heaps may occur!

## List of Overrides:

The specific functions that get redirected to the mimalloc library are:

// C
void* malloc(size_t size);
void* calloc(size_t size, size_t n);
void* realloc(void* p, size_t newsize);
void free(void* p);
void* aligned_alloc(size_t alignment, size_t size);
char* strdup(const char* s);
char* strndup(const char* s, size_t n);
char* realpath(const char* fname, char* resolved_name);
// C++
void operator delete(void* p);
void operator delete[](void* p);
void* operator new(std::size_t n) noexcept(false);
void* operator new[](std::size_t n) noexcept(false);
void* operator new( std::size_t n, std::align_val_t align) noexcept(false);
void* operator new[]( std::size_t n, std::align_val_t align) noexcept(false);
void* operator new ( std::size_t count, const std::nothrow_t& tag);
void* operator new[]( std::size_t count, const std::nothrow_t& tag);
void* operator new ( std::size_t count, std::align_val_t al, const std::nothrow_t&);
void* operator new[]( std::size_t count, std::align_val_t al, const std::nothrow_t&);
// Posix
int posix_memalign(void** p, size_t alignment, size_t size);
// Linux
void* memalign(size_t alignment, size_t size);
void* valloc(size_t size);
void* pvalloc(size_t size);
size_t malloc_usable_size(void *p);
void* reallocf(void* p, size_t newsize);
// macOS
void vfree(void* p);
size_t malloc_size(const void* p);
size_t malloc_good_size(size_t size);
// BSD
void* reallocarray( void* p, size_t count, size_t size );
void* reallocf(void* p, size_t newsize);
void cfree(void* p);
// NetBSD
int reallocarr(void* p, size_t count, size_t size);
// Windows
void* _expand(void* p, size_t newsize);
size_t _msize(void* p);
void* _malloc_dbg(size_t size, int block_type, const char* fname, int line);
void* _realloc_dbg(void* p, size_t newsize, int block_type, const char* fname, int line);
void* _calloc_dbg(size_t count, size_t size, int block_type, const char* fname, int line);
void* _expand_dbg(void* p, size_t size, int block_type, const char* fname, int line);
size_t _msize_dbg(void* p, int block_type);
void _free_dbg(void* p, int block_type);