emalloc is a simple, hybrid memory allocator implementation in C featuring three distinct allocation strategies optimized for different allocation sizes. It provides drop-in replacements for standard malloc, free, calloc, and realloc with comprehensive debugging capabilities.
The allocator uses a three-tier strategy to optimize for different allocation patterns:
Handles small allocations in the range of 32 bytes to 8 KiB.
- Fixed-size object allocation within slabs (64 KiB per slab)
- Efficient bitmap-based free tracking
- Minimal fragmentation for small objects
- Separate chains for each object size class
Handles medium allocations in the range of 16 KiB to 1 MiB.
- Power-of-2 based allocation strategy
- Efficient memory coalescing on free
- Manages large arenas (8 MiB each) to reduce fragmentation
- Integrates slab allocations within buddy-managed arenas
Handles large allocations >1 MiB.
- Direct memory mapping via
mmap() - Minimal overhead for single large allocations
- Proper alignment and deallocation tracking
- Drop-in replacement: Compatible with
malloc(),free(),calloc(), andrealloc() - Thread-safe: Global spinlock protects all allocator operations
- GCC or compatible C compiler
- Linux environment (uses
brk()andmmap()system calls) - GNU Make
# Build optimized release version
make build
# Build with debug symbols
make VARIANT=DEBUG build
# Clean build artifacts
make clean
# Clean and rebuild
make freshThe build produces libemalloc.so, a shared library that can be preloaded via LD_PRELOAD.
LD_PRELOAD=./libemalloc.so ./your_programInclude the header and link against the library:
#include "emalloc.h"
int main() {
void* ptr = emalloc(1024);
// Use ptr...
efree(ptr);
return 0;
}A test harness (test/run_trace.c) validates allocator correctness by replaying allocation traces:
./test/run_trace <path/to/libemalloc.so> <trace_file>The trace format is:
- Header:
<total_ops> <num_allocs> <num_frees> - Operations:
a <id> <size>(allocate) orf <id>(free)
Example trace:
3 2 1
a 0 128
a 1 256
f 0
The test verifies:
- Allocation success and correct size tracking
- Data integrity across allocate-free cycles
void* emalloc(size_t size); // Allocate memory
void* ecalloc(size_t count, size_t size); // Allocate and zero
void* erealloc(void *ptr, size_t size); // Resize allocation
void efree(void* ptr); // Deallocate memory
size_t emalloc_usable_size(void *ptr); // Get allocation size// Currently implemented symbols
void* malloc(size_t size); // Allocate memory
void* calloc(size_t count, size_t size); // Allocate and zero
void* realloc(void *ptr, size_t size); // Resize allocation
void free(void* ptr); // Deallocate memory
size_t malloc_usable_size(void *ptr); // Get allocation size
// Planned symbols:
// posix_memalign
// aligned_alloc
// reallocarray
// memalign
// valloc/pvalloc- Slab allocator:
slab_alloc(),slab_free(),slab_usable_size() - Buddy allocator:
buddy_alloc(),buddy_free(),buddy_usable_size(),buddy_alloc_slab() - mmap allocator:
mmap_alloc(),mmap_free(),mmap_usable_size() - Heap management:
brk_allocate_buddy_arena(),brk_get_allocated_heap_end() - Synchronization:
spin_lock(),spin_unlock()
All allocations are tracked via headers:
- Slab headers contain magic numbers, object size/count, free lists, and bitmap
- Buddy headers contain magic numbers, arena bookkeeping, and per-size bitmaps
- mmap headers contain magic numbers and allocation metadata
The allocator seamlessly transitions between strategies:
- Small allocations ≤8 KiB → slab
- Medium allocations 8 KiB-1 MiB → buddy
- Large allocations >1 MiB → mmap
The buddy allocator can internally use slab allocations for efficient medium-object handling.
A global spinlock serializes all allocator operations, ensuring thread-safe access to shared data structures. The lock is held for minimal duration during fast-path allocations.
- All configuration values are powers of 2 for efficient bit manipulation
- Changing allocation size parameters may break existing functionality (see
econfig.hfor constraints) - The allocator assumes 4 KiB (2^12) page size for mmap operations
- Spinlock implementation may not be optimal for highly contended scenarios
- emalloc.h/c: Main API and dispatch logic
- eslab.c: Slab allocator implementation
- ebuddy.c: Buddy allocator implementation
- emmap.c: mmap-based allocator
- ebrk.c: Heap management via
brk() - espinlock.c: Spinlock synchronization
- eutil.c: Utility functions
- eapi.c: Wrapper for standard malloc/free symbols
- econfig.h: Configuration and constants