A portable, thread-safe private heap allocator for C/C++.
pheap is a lightweight memory allocator library that provides private heap management with zero external dependencies. It is designed for environments where the standard allocator is unavailable or unsuitable:
- WebAssembly - Custom memory management for WASM modules
- OS Development - Kernel and bootloader memory allocation
- Embedded Systems - Resource-constrained environments
- Game Engines - Dedicated heaps for subsystems with predictable lifetimes
- Sandboxed Applications - Isolated memory regions
- Dynamic and fixed-size heap modes
- Thread-safe with multiple lock backends (Win32, pthread, internal spinlock)
- Executable memory allocation support
- Custom memory and lock backends
- Cross-platform: Windows, Linux, macOS, ARM, x86
- Zero external dependencies
- Drop-in malloc/free replacement
- C++ compatible
#include "pheap.h"
int main() {
// Create a thread-safe heap
pheap_t heap = pheap_create(PHEAP_FLAG_THREADSAFE);
// Allocate memory
void *ptr = pheap_alloc(heap, 1024);
// Use the memory...
// Free when done
pheap_free(heap, ptr);
// Destroy the heap
pheap_destroy(heap);
return 0;
}Add pheap.c and pheap.h to your project and compile with your existing build system.
To build as a static library:
# Linux/macOS
./build.sh
# Windows
build.batThis produces libpheap.a (Unix) or pheap.lib (Windows).
// Create a dynamic heap that grows as needed
pheap_t pheap_create(uint32_t flags);
// Create a heap within a fixed memory region (no system allocations)
pheap_t pheap_create_fixed(void *memory, size_t size, uint32_t flags);
// Create a heap with custom memory allocation callbacks
pheap_t pheap_create_custom(uint32_t flags, const pheap_alloc_config_t *config);// Allocate memory
void *pheap_alloc(pheap_t h, size_t size);
// Allocate zeroed memory
void *pheap_zalloc(pheap_t h, size_t size);
// Reallocate memory
void *pheap_realloc(pheap_t h, void *p, size_t size);
// Free memory
void pheap_free(pheap_t h, void *p);
// Get the size of an allocation
size_t pheap_msize(const void *p);// Destroy the heap and free all memory
void pheap_destroy(pheap_t h);When PHEAP_USE_GLOBAL_HEAP is enabled:
void *pheap_g_alloc(size_t size);
void *pheap_g_zalloc(size_t size);
void *pheap_g_realloc(void *p, size_t size);
void pheap_g_free(void *p);Configure pheap by defining these macros before including pheap.h. All options must be defined to a value (0 or 1), not just defined/undefined.
| Option | Default | Description |
|---|---|---|
PHEAP_ALIGNMENT |
0x10 |
Memory alignment (must be power of two, set to 1 for no alignment) |
PHEAP_PAGE_SIZE |
0x1000 |
Native page size (must be power of two) |
PHEAP_USE_GLOBAL_HEAP |
0 |
Enable global heap accessible anywhere |
PHEAP_GLOBAL_REPLACE_MALLOC |
0 |
Replace malloc/calloc/realloc/free with global heap |
PHEAP_MEMBLOCK_SIZE_HINT |
32 * 0x100000 |
Default memory block size (must be >= page size) |
PHEAP_USE_THREAD_CACHE |
0 |
Per-thread allocation cache for the global heap (requires PHEAP_USE_GLOBAL_HEAP=1) |
PHEAP_INTERNAL_DEBUG |
0 |
Enable debugging support for tests |
| Option | Value | Description |
|---|---|---|
PHEAP_LOCK_PRIMITIVE |
PHEAP_NO_LOCK (0) |
Disable all locking |
PHEAP_WIN32_LOCK (1) |
Use Win32 CRITICAL_SECTION | |
PHEAP_PTHREAD_LOCK (2) |
Use pthread_mutex_t | |
PHEAP_INTERNAL_LOCK (3) |
Use internal cross-platform spinlock |
Default: PHEAP_WIN32_LOCK on Windows, PHEAP_PTHREAD_LOCK elsewhere.
Pass these flags to pheap_create() and pheap_create_fixed():
| Flag | Description |
|---|---|
PHEAP_FLAG_EXEC |
Allocate memory as executable (for JIT compilation) |
PHEAP_FLAG_THREADSAFE |
Enable thread-safe operations (requires locking enabled) |
Define PHEAP_OVERRIDE_SYSTEM_HEADER to provide custom memory primitives:
#define PHEAP_OVERRIDE_SYSTEM_HEADER "my_system.h"Your header must provide:
// Type definitions
size_t, intNN_t, uintNN_t, intptr_t, uintptr_t
// Memory operations
void *pheap_memset(void *s, int c, size_t n);
void *pheap_memcpy(void *dest, const void *src, size_t n);
// System allocation
void *pheap_system_alloc(size_t n, int exec);
void pheap_system_free(void *p, size_t n);Define PHEAP_OVERRIDE_LOCK_HEADER to provide custom lock primitives:
#define PHEAP_OVERRIDE_LOCK_HEADER "my_locks.h"Your header must provide:
typedef /* your lock type */ pheap_lock_t;
void pheap_init_lock(pheap_lock_t *lock);
void pheap_uninit_lock(pheap_lock_t *lock);
void pheap_lock_lock(pheap_lock_t *lock);
void pheap_unlock_lock(pheap_lock_t *lock);Use pheap_create_custom() with runtime callbacks:
void *my_alloc(size_t n, void *context) {
return my_memory_pool_alloc(context, n);
}
void my_free(void *p, size_t n, void *context) {
my_memory_pool_free(context, p, n);
}
pheap_alloc_config_t config = {
.custom_alloc = my_alloc,
.custom_free = my_free,
.context = my_pool,
.memblock_size = 0 // 0 = use default
};
pheap_t heap = pheap_create_custom(0, &config);# Build static library (release)
./build.sh # Linux/macOS
build.bat # Windows
# Build with debug symbols
DEBUG=yes ./build.sh
# Clean build artifacts
./build.sh clean# Run all tests
./test.sh # Linux/macOS
test.bat # Windows| Variable | Description |
|---|---|
DEBUG |
Set to yes for debug build with symbols |
TEST_SEED |
Seed for random number generator in tests |
NUM_TESTS |
Number of test iterations to run |
CC=clang CXX=clang++ ./build.sh| Platform | Compilers | Architectures |
|---|---|---|
| Windows | MSVC, MinGW, Clang | x86, x64, ARM64 |
| Linux | GCC, Clang | x86, x64, ARM32, ARM64 |
| macOS | Clang, GCC | x64, ARM64 |
This project is released into the public domain (Unlicense). You are free to use, modify, and distribute this code without restriction.