Use when implementing a custom malloc/free-style memory allocator from first principles — not when just using a language's built-in allocator. Triggers on: 'write a malloc implementation', 'build a memory allocator', 'free list allocator', 'buddy allocator', 'slab allocator', 'implement my own malloc/free'. Covers free-list design, block metadata, coalescing, alignment, and allocator strategy tradeoffs.
Scanned 9/9/2026
Install to Claude Code
npx -y skills add yanacuti1121/Yana-AI --skill memory-allocator-from-scratch --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Memory Allocator From Scratch?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/yanacuti1121-memory-allocator-from-scratch)More formats (shields.io, HTML) on the badges page.
---
name: memory-allocator-from-scratch
description: "Use when implementing a custom malloc/free-style memory allocator from first principles — not when just using a language's built-in allocator. Triggers on: 'write a malloc implementation', 'build a memory allocator', 'free list allocator', 'buddy allocator', 'slab allocator', 'implement my own malloc/free'. Covers free-list design, block metadata, coalescing, alignment, and allocator strategy tradeoffs."
origin: yana-ai — synthesized from classic allocator literature (K&R malloc, dlmalloc design notes, jemalloc/tcmalloc public design docs) and community from-scratch tutorials indexed in codecrafters-io/build-your-own-x
license: Apache-2.0
version: 1.0.0
compatibility: yana-ai >= 0.43.2
---
# /memory-allocator-from-scratch
## When to Use
- Implementing `malloc`/`free`/`realloc` semantics from raw memory (e.g. over `mmap`/`sbrk`, or a fixed byte array) for teaching, an embedded target, or a custom-runtime project.
- Choosing between allocator strategies (bump, free-list, buddy, slab) for a specific workload and needing the actual tradeoffs, not just the names.
- Debugging fragmentation, use-after-free, or double-free in a hand-rolled allocator.
## Do NOT use for
- Application-level memory management in a language with a GC or a mature allocator (JS, Python, Go, Java) — there is nothing to build here, use the runtime's allocator.
- General performance profiling of memory usage — see `memory-leak-detection` and `profiling-benchmarking` instead.
- Production allocator replacement — use jemalloc/mimalloc/tcmalloc; this skill is for understanding the mechanism, not shipping a faster malloc than decades of tuned production allocators.
---
## Strategy Decision
```
Need the simplest possible allocator, never freeing individual objects?
→ Bump allocator (Step 1) — O(1) alloc, no free, reset all at once
Need general alloc/free of variable sizes, simplicity over raw speed?
→ Free-list allocator (Step 2) — the "classic malloc" approach
Need to minimize external fragmentation with fast coalescing?
→ Buddy allocator (Step 3) — power-of-2 sizes, easy merge, some internal waste
Need fast alloc/free of many same-sized objects (e.g. a fixed struct)?
→ Slab allocator (Step 4) — pre-carved fixed-size slots, near-zero overhead per alloc
```
## Step 1: Bump Allocator (baseline)
Simplest possible allocator: keep one pointer to the next free byte, hand out `size` bytes and advance the pointer. No `free()` — the whole arena resets or is discarded at once (common in arena/region allocators for a single request's lifetime, e.g. a per-frame game allocator or a per-HTTP-request arena).
```
alloc(size):
aligned = align_up(next_free, ALIGNMENT)
if aligned + size > arena_end: return OUT_OF_MEMORY
next_free = aligned + size
return aligned
```
## Step 2: Free-List Allocator
The mechanism behind classic `malloc`. Every allocated AND free block gets a small header before the returned pointer:
```
struct BlockHeader {
size_t size; // payload size, not including header
bool is_free;
BlockHeader* next; // intrusive linked list of free blocks
}
```
`alloc(size)`: walk the free list looking for a block big enough.
- **First-fit**: take the first block that fits — fast, can fragment.
- **Best-fit**: scan for the smallest block that fits — less waste per allocation, slower, can leave many tiny unusable fragments over time.
- If the found block is much bigger than needed, **split** it: carve off the requested size, leave the remainder as a new (smaller) free block.
`free(ptr)`: walk back from `ptr` to its header, mark `is_free = true`, then **coalesce** with adjacent free blocks (check the block immediately before and after in memory address order, merge if both are free) — without coalescing, freed memory fragments into unusable slivers over time even though total free bytes is fine.
**Alignment**: most platforms require allocations aligned to 8 or 16 bytes (SIMD types need more). Round the requested size up to the alignment boundary before computing block size — an unaligned pointer returned to the caller can crash on some architectures (e.g. ARM strict alignment) or silently corrupt SIMD loads.
## Step 3: Buddy Allocator
Only allocates in power-of-2 sizes. The whole arena starts as one free block of size `2^max`. To satisfy a request, repeatedly split the smallest available block in half ("buddies") until you reach the smallest power-of-2 that fits the request. To free, check if your buddy (computable directly from your address via XOR with the block size) is also free — if so, merge back into the parent block, and recurse the check upward.
Tradeoff vs free-list: coalescing is O(log n) and address-computable (no list walk needed to find the buddy), but every allocation rounds up to the next power of 2 — a 65-byte request costs 128 bytes (internal fragmentation).
## Step 4: Slab Allocator
For a workload that allocates/frees many objects of the SAME fixed size (e.g. kernel `task_struct`, a game's particle objects): pre-allocate a "slab" (a page or arena) already carved into fixed-size slots, and track free slots with a simple bitmap or intrusive free list of slot indices. Alloc and free are both O(1) with no header-walking or fragmentation concerns, since every slot is identical size.
## What NOT to Do
- Don't skip the header — without per-block metadata, `free()` has no way to know a block's size or its free-list neighbors.
- Don't forget alignment — misaligned pointers are a portability bug that won't show up on every platform/compiler, making it easy to ship broken and not notice.
- Don't free() without coalescing adjacent blocks — a free-list allocator that never merges will eventually report "out of memory" while holding plenty of free (but fragmented) bytes.
- Don't reach for buddy or slab allocators before a free-list works correctly — they solve fragmentation/speed problems a working free-list doesn't have yet.
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!