5 releases
new 0.2.1 | Nov 28, 2024 |
---|---|
0.2.0 | Nov 26, 2024 |
0.1.2 | Nov 20, 2024 |
0.1.1 | Nov 20, 2024 |
0.1.0 | Nov 20, 2024 |
#147 in Memory management
410 downloads per month
255KB
4K
SLoC
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.
Global Allocator
To use this crate as your global allocator:
use portable_dlmalloc::DLMalloc;
#[global_alloactor] 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.
If you need to use a different alignment for some specific reasons, use dlmemalign
function to implement your GlobalAlloc
trait.
Alternate Allocator
The Allocator Trait is currently nightly-only. You are required to use a nightly rust compiler in order to use this feature.
To use alternate alloactor, you will have to declare that your crate uses allocator_api
:
#![feature(allocator_api)]
You also need to enable alt-alloc
in Cargo.toml
section:
[dependencies.portable-dlmalloc]
version = "0.2.1"
features = ["alt-alloc"]
To use alternate allocator, you need to create an allocator:
use portable_dlmalloc::AltAlloc;
let a=AltAlloc::new(0,false);
{
let ap:Box::<u32,AltAlloc>=Box::new_in(123,a);
println!("{:p} | {}",&raw const *ap,ap);
// "ap" will be automatically dropped here as "ap"'s lifetime will end at the end of the scope.
// This is why "ap" is created in a brace.
// Otherwise, you need to manually call "drop" function before you destroy the allocator.
}
// Make sure you have dropped everything you allocated from this allocator before you destroy this allocator!
a.destroy();
Please note that alternate allocator is a nightly-only API. If Rust removes this feature in future, this feature will be removed from this crate as well.
Caveat: You must ensure all allocations are dropped before destroying the alternate allocator!
Personal Throughts: The Rust's Allocator APIs should borrow the allocator objects before it's stablized. In other words, it should be like:
let a=AltAlloc::new(0,false);
let ap:Box::<u32,AltAlloc>=Box::new_in(123,&a);
let aq:Box::<u64,AltAlloc>=Box::new_in(321,&a);
In this case, AltAlloc
can implement Drop
trait, and a
, ap
, aq
can be dropped properly and automatically with RAII rule.
Current implementation of AltAlloc
has to implement Copy
trait in order to allow multiple allocations within a single alternate allocator.
In summary, I believe:
Allocator
trait should reject theCopy
trait.Allocator
trait should require theDrop
trait.
Raw FFI
The raw
module from this crate exports FFI bindings for dlmalloc
library.
use portable_dlmalloc::raw::*;
For example, you may use dlmallopt
to adjust mmap
granularity (default is 2MiB in Rust crate):
dlmallopt(M_GRANULARITY,0x20000); // Change `mmap` granularity to 128KiB.
You may use dlpvalloc
to allocate memory on page-granularity.
let p=dlpvalloc(12345);
assert_eq!(p as usize & 0xfff,0);
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(4096) as usize;
let q=dlpvalloc(4096) as usize;
// Consecutive allocations do not guarantee them to be adjacent.
assert_eq!(q-p,8192);
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.mmap
should return(void*)-1
to indicate failure instead ofNULL
.munmap
should return0
to indicate success, and-1
to indicate failure.#[no_mangle] unsafe extern "C" custom_mmap(length:usize)->*mut c_void; #[no_mangle] unsafe extern "C" custom_munmap(ptr:*mut c_void,length:usize)->i32;
custom_direct_mmap
: Extend the allocated pages. This is optional. Return(void*)-1
to indicate failure/no-support.#[no_mangle] unsafe extern "C" custom_mmap(length:usize)->*mut c_void;
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.#[no_mangle] unsafe extern "C" init_lock(lock:*mut *mut c_void); // Initialize the mutex. #[no_mangle] unsafe extern "C" final_lock(lock:*mut *mut c_void); // Finalize the mutex. #[no_mangle] unsafe extern "C" acquire_lock(lock:*mut *mut c_void); // Acquire the mutex. #[no_mangle] unsafe extern "C" release_lock(lock:*mut *mut c_void); // Release the mutex.
custom_abort
: Implementabort()
routine.dlmalloc
callscustom_abort()
when internal assertion fails. You may use panic here.#[no_mangle] unsafe extern "C" custom_abort()->!;
memcpy
/memset
: I suppose no explanations are needed for these two.dlmalloc
uses 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.
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 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
)
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.
No runtime deps
~0–280KB