ZigProjects

Zig Project: Custom Memory Pool

TT
TopicTrick Team
Zig Project: Custom Memory Pool

Zig Project: Custom Memory Pool

For your Phase 3 project, you will move beyond using std.mem.Allocator. You will Build Your Own. You will architect a Type-Safe Fixed Pool Allocator.

  • The Problem: General purpose allocators are slow because they have to "Search" for space.
  • The Solution: Your allocator will pre-allocate memory for $1,000$ items of a specific type.
  • The Result: Allocation happens in exactly 2 CPU cycles.

This 1,500+ word guide explores the "Bitmask-Free" strategy of Free Lists and how to use Zig's Union and Pointers to create a zero-overhead management layer.


1. The Physics of the Heap: Fragmentation and Paging

To build a better allocator, you must understand why the standard one fails in high-performance environments.

The Heap Mirror

  • External Fragmentation: In a general-purpose heap (like malloc), memory is a series of holes. If you allocate a 100-byte block, then a 200-byte block, and free the first one, you have a 100-byte hole. Over time, these holes become too small to use, wasting RAM.
  • Paging Latency: If your allocator jumps randomly across the virtual address space, the MMU (Memory Management Unit) must perform expensive Page Table Walks to find the physical RAM.
  • The Zig Strategy: By using a Memory Pool, we allocate a single, contiguous block of RAM. This ensures perfect Spatial Locality, keeps the CPU cache warm, and eliminates fragmentation by design.

2. Requirement 1: The "Free List" Strategy

How do you know which "Slot" in your pool is empty?

  • You could use a "Bitmask" (a list of 0s and 1s). Too Slow.
  • The Solution: A Linked Stack inside the RAM.
  • When a slot is "Free," you store a pointer to the NEXT free slot inside the slot itself.
  • When you need a slot, you pop it from the stack.
  • This is the fastest way to manage memory ever invented.

2. Requirement 2: Type Safety (The Comptime Guard)

Your allocator must be restricted to a specific type to ensure speed.

zig

Why this is Professional: Because T is known at compile-time, the CPU doesn't have to calculate "Sizes" or "Offsets" during the allocation. Everything is "Hard-coded" into the binary for speed.


4. Atomic Internals: Wait-Free Memory Dispatch

In a multi-threaded game engine, multiple threads might ask for a new "Bullet" object simultaneously.

The Atomic Mirror

  • The Problem: A standard Mutex is a "Blocking" operation. If Thread A holds the lock, Thread B must stop and wait for the OS to reschedule it (~1000+ cycles).
  • The Physics: We use Atomic Load/Store and Compare-And-Swap (CAS).
  • The Result: The "Free List" pointer is updated in a single hardware transaction. No thread ever "Stops." This is Wait-Free and provides the maximum possible throughput for high-frequency allocation across multiple CPU cores.

5. Requirement 3: Multi-Core Safety

If 5 threads use your Pool at the same time, the "Free List" will be corrupted.

  • You must implement Atomic Pointers (Module 190).
  • Use Compare-And-Swap (CAS) to ensure that only one thread can "Pop" a slot at a time.
  • This is called a Wait-Free algorithm. It is the gold standard for high-performance concurrency.

4. Requirement 4: The "Zig Allocator" Interface

To be a "Good Citizen," your Pool must work with the rest of the Zig ecosystem.

  • You must create an Interface Struct (Module 181).
  • Your Pool should expose a function: pub fn allocator(self: *Self) std.mem.Allocator { ... }.
  • This allows a user to pass your Pool into any standard Zig library, and the library will use your high-speed logic without even knowing it!

5. Testing: The "Torture Test"

How do you prove your Pool doesn't leak?

  • Write a test that allocates $1,000$ items, then frees $500$ of them in a random order.
  • Then allocate $200$ more.
  • Verify that every pointer is unique and no memory is "Double-used" or "Lost."

This project is the transition from "Writing logic" to "Architecting Infrastructure." By mastering the interaction between pointers and raw RAM blocks, you gain the ability to build the memory engines that power Games, Databases, and Operating Systems. You graduate from "Managing objects" to "Architecting the Heap itself."


Phase 29: Memory Architecture Checklist

  • Audit your Alignment: Ensure your pool slots are aligned to the host CPU's cache line size (usually 64 bytes) to prevent "False Sharing."
  • Implement Wait-Free Logic: Use std.atomic.Value to manage your free list head for thread-safe, non-blocking allocation.
  • Use Static Pool Sizing: For embedded or real-time work, define your pool size at comptime to ensure $0$ runtime heap calls.
  • Support the Allocator Interface: Wrap your pool in a std.mem.Allocator struct so it can be used with std.ArrayList and other containers.
  • Verify Fragmentation Resistance: Use a memory debugger to confirm that your pool never leaves small "holes" in the RAM after 1,000,000 allocation cycles.

Read next: Zig Mastery Graduation: The Final Assessment →


Part of the Zig Mastery Course — engineering the heap.