portable-dlmalloc
Portable Fork of Doug Lea's malloc Implementation for Rust.
Introduction
This code is originally implemented by Doug Lea. The original source code is no longer available from the FTP URL listed in the website, but you can still find it through Wayback Machine.
You may use this crate to help you make a portable global allocator.
You will have to implement the eight C functions as described in Port To Your Platform chapter.
dlmalloc guarantees the alignment of allocation in comparison to just some wrappers on malloc functions (e.g.: wrapping HeapAlloc in Windows). If your structure is defined to be aligned on a big alignment (e.g.: 1024 bytes), this allocator guarantees the returned pointer if aligned on your specific boundary. The minimum alignment of dlmalloc is four times of the pointer size. (e.g.: 32 bytes on 64-bit platform.)
Specify Default Granularity
To specify a default granularity, you should define an environment variable DEFAULT_MMAP_GRANULARITY before you compile.
For instance, to define the granularity to 64K in Windows:
set DEFAULT_MMAP_GRANULARITY=0x10000
Or in Linux:
You must specify a granularity to be a integer power of two. Note: only 0x prefix is recognized by the build script. This means you can only use either hexadecimal or decimal integers.
Global Allocator
To use this crate as your global allocator:
use DLMalloc;
static GLOBAL_ALLOCATOR:DLMalloc=DLMalloc;
Then you will be able to use alloc crate.
extern crate alloc;
The default alignment of alloc trait method automatically determines the required alignment.
Your custom_mmap implementation must track all allocated pages so that you can release pages in shared address-space (e.g.: DLL in Windows, SO in Linux).
The final_lock routine will not be called for the global allocator! Your init_lock implementation must track all initialized locks so that you can finalize all locks, unless it is trivial to finalize the locks.
Mspace Allocator
You can also use MspaceAlloc as your global allocator:
use portable_dlmalloc:MspaceAlloc;
static GLOBAL_ALLOCATOR:MspaceAlloc=new;
To destroy this allocator:
unsafe
Use this allocator only if:
- You need a specific initial capacity bigger than default granularity.
- You need to destroy the allocator in one-shot, without tracing all allocated pages.
Alternate Allocator
The Allocator Trait is currently nightly-only. Therefore, the alternate allocator feature is only available in the 0.x version of this crate. This feature will not be included in 1.x version and later until the Allocator Trait is stablized.
Raw FFI
The raw module from this crate exports FFI bindings for dlmalloc library.
use *;
For example, you may use dlmallopt to adjust mmap granularity (default is 2MiB in Rust crate):
dlmallopt; // Change `mmap` granularity to 128KiB.
You may use dlpvalloc to allocate memory on page-granularity.
let p=dlpvalloc;
assert_eq!;
Warning: dlpvalloc - as well as other routines that allocate memories with higher granularities - may cause serious memory fragmentation if you overrely on them.
// Assume 4096 is page size.
let p=dlpvalloc as usize;
let q=dlpvalloc as usize;
// Consecutive allocations do not guarantee them to be adjacent.
assert_eq!;
Port to Your Platform
To port dlmalloc to your platform, implement the following procedures:
custom_mmap/custom_munmap: Allocate and free pages from the system.mmapshould return(void*)-1to indicate failure instead ofNULL.munmapshould return0to indicate success, and-1to indicate failure.
Hint: If you are in baremetal environment withoutunsafe extern "C" custom_mmap; unsafe extern "C" custom_munmap;mmap-like services like outdated embedded systems, you can just return the pointer to the free memory.
Note: This crate does not supportsbrk, even though original implementation ofdlmallocsupports it. Just emulate the behavior ofmmapwithsbrk.init_lock/final_lock/acquire_lock/release_lock: Implement thread-safety fordlmalloc. The minimal implementation can be a simple spinlock. You can leave the implementations empty for this set of routines if you do not need thread-safety.
The exact type oflockdepends on your implementation. It can be*mut Twhere T can be anything that has the size of a pointer.unsafe extern "C" init_lock; // Initialize the mutex. unsafe extern "C" final_lock; // Finalize the mutex. unsafe extern "C" acquire_lock; // Acquire the mutex. unsafe extern "C" release_lock; // Release the mutex.custom_abort: Implementabort()routine.dlmalloccallscustom_abort()when internal assertion fails. You may use panic here.
Note thatunsafe extern "C" custom_abort!;messageandsrc_fileare null-terminated strings. The encodings of the string is implementation-specific of the C compiler. It is your duty to convert them into UTF-8 encoding.
Themessagestring is guaranteed to contain ASCII characters only. However,src_filemay contain non-ASCII characters.memcpy/memset: I suppose no explanations are needed for these two.dlmallocuses these two routines, but they can be easily implemented anyway. You do not need to implement these two routines in Rust if your linker can find libraries that implement these two routines. Note that MSVC SDK provides source code of high-performancememcpyandmemsetimplementations in Assembly!
Note: If you are using Rust 2024 or higher, you must use #[unsafe(no_mangle)] as prefix! See Rust unsafe attributes for more details.
If, for some reasons, these procedure names must be reserved in your project, you may use the export_name attribute. Note that export_name attribute requires unsafe in Rust 2024 as well as no_mangle!
Build
Since the core of the dlmalloc library is written in C, a working C compiler is required.
If your target is somewhat unorthodox, you need to set the following environment variables before executing cargo build:
CC: This environment variable specifies which compiler executable should be used to compilemalloc.c.AR: This environment variable specifies which archiver executable should be used to archive this crate into a static library.CFLAGS: This environment variable specifies additional flags to the compiler. You might need this flag to add debug information (e.g.:-g). In kernel-mode with MSVC toolchain, you might need/GS-flag.
If cc crate does not know how to invoke your compiler and/or archiver, you should write a script to emulate cc and/or ar.
In most circumstances, setting CC to clang and AR to llvm-ar should work well.
License
This crate is under the MIT license.