Skip to main content
skill CX Codex

custom-allocators — Claude Code skill: what it does, how to install

Guides agents through designing custom C and Rust memory allocators, tuning jemalloc or mimalloc, and measuring heap fragmentation.

Install into Claude Code · Skills CLI (Vercel) All methods and platforms ↓
npx skills add mohitmishra786/low-level-dev-skills --skill custom-allocators -a claude-code
Open on GitHub

What custom-allocators does

The skill equips coding agents with reference implementations for fixed-size pool allocators and bump arenas in C. Instead of routing every allocation through generic libc malloc, it shows how to use linear arenas for per-request lifetimes where an entire block resets at once.

It covers runtime configuration for jemalloc and mimalloc via LD_PRELOAD alongside environment flags like MALLOC_CONF. For Rust projects, it demonstrates implementing the GlobalAlloc trait to track allocations or run in #![no_std] targets.

Memory leaks in arenas happen when resets are skipped between loop iterations or server frames. In Rust, passing a mismatched Layout to dealloc triggers undefined behavior, so the skill notes storing size and alignment alongside raw pointers.

What it helps with

  • implement a fast O(1) fixed-size block pool in C
  • build a request-scoped bump arena allocator with reset
  • tune jemalloc dirty page purging via MALLOC_CONF
  • implement the Rust GlobalAlloc trait for allocation tracking

Example prompts for the agent

  • Write an aligned bump arena allocator in C with an arena_reset function
  • Show the MALLOC_CONF settings to tune dirty page decay in jemalloc
  • Implement a tracking allocator in Rust using the GlobalAlloc trait

How to install custom-allocators

1Skills CLI (Vercel)

npx skills add mohitmishra786/low-level-dev-skills --skill custom-allocators -a claude-code

2Manually: put the files in place

~/.claude/skills/custom-allocators/SKILL.md

Copy the whole skill folder; for one project use .claude/skills/custom-allocators/

Step by step, with commands for each platform: How to install skills in Claude Code: five ways

Questions about custom-allocators

How do I install custom-allocators in Claude Code?

Run npx skills add mohitmishra786/low-level-dev-skills --skill custom-allocators -a claude-code in your terminal. You can also place the file directly at ~/.claude/skills/custom-allocators/SKILL.md.

What does custom-allocators do?

It provides patterns and code templates for memory strategies like pools and arenas. It also includes tuning guides for production allocators such as jemalloc and mimalloc.

How does the arena allocator handle individual deallocations?

It does not support individual frees. Memory is claimed by incrementing an offset pointer, and all allocated space is recycled simultaneously by resetting the offset to zero.

Source text

SKILL.md · MIT
---
name: custom-allocators
description: Custom allocator skill for memory allocation strategies. Use when implementing pool/slab/arena allocators, tuning jemalloc/mimalloc, writing Rust GlobalAlloc, or benchmarking allocator performance. Activates on queries about jemalloc, mimalloc, tcmalloc, arena allocator, GlobalAlloc, or fragmentation.
---

# Custom Allocators

## Purpose

Guide agents through memory allocator design and tuning: pool/slab/arena/buddy taxonomy, jemalloc internals and `MALLOC_CONF`, mimalloc design, tcmalloc thread-caching, writing a simple pool allocator in C, Rust `GlobalAlloc` trait, fragmentation metrics, and benchmarking.

## When to Use

- Replacing malloc for latency-sensitive or embedded workloads
- Tuning jemalloc/mimalloc for server heap behavior
- Implementing arena allocation for request-scoped or frame-based lifetimes
- Writing a Rust custom global allocator for `no_std` or performance
- Diagnosing heap fragmentation (internal vs external)
- Benchmarking allocator throughput and latency

## Workflow

### 1. Allocator taxonomy

```
Allocator types
├── Pool/fixed-size — O(1) alloc/free, fixed block sizes
├── Slab — kernel-style, cache-friendly size classes
├── Arena/bump — fast alloc, bulk free (reset arena)
├── Buddy — power-of-two blocks, low fragmentation for large allocs
└── General (malloc) — jemalloc, mimalloc, tcmalloc
```

### 2. Simple pool allocator in C

```c
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>

typedef struct pool_block {
    struct pool_block *next;
} pool_block_t;

typedef struct {
    void   *memory;
    size_t  block_size;
    size_t  num_blocks;
    pool_block_t *free_list;
} pool_t;

int pool_init(pool_t *p, size_t block_size, size_t num_blocks) {
    p->block_size = block_size < sizeof(pool_block_t) ?
        sizeof(pool_block_t) : block_size;
    p->num_blocks = num_blocks;
    p->memory = aligned_alloc(64, p->block_size * num_blocks);
    if (!p->memory) return -1;
    p->free_list = NULL;
    for (size_t i = 0; i < num_blocks; i++) {
        pool_block_t *blk = (pool_block_t *)((char *)p->memory + i * p->block_size);
        blk->next = p->free_list;
        p->free_list = blk;
    }
    return 0;
}

void *pool_alloc(pool_t *p) {
    if (!p->free_list) return NULL;
    pool_block_t *blk = p->free_list;
    p->free_list = blk->next;
    return blk;
}

void pool_free(pool_t *p, void *ptr) {
    pool_block_t *blk = (pool_block_t *)ptr;
    blk->next = p->free_list;
    p->free_list = blk;
}
```

### 3. Arena allocator

```c
typedef struct {
    char  *base;
    size_t capacity;
    size_t offset;
} arena_t;

void *arena_alloc(arena_t *a, size_t size, size_t align) {
    uintptr_t cur = (uintptr_t)(a->base + a->offset);
    uintptr_t aligned = (cur + align - 1) & ~(align - 1);
    size_t padding = aligned - cur;
    if (a->offset + padding + size > a->capacity)
        return NULL;
    a->offset += padding + size;
    return (void *)aligned;
}

void arena_reset(arena_t *a) { a->offset = 0; }
```

Use per-request arenas in servers — reset after response, no per-object free.

### 4. jemalloc tuning

```bash
# Use jemalloc as system allocator
LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2 ./myapp

# Runtime tuning
export MALLOC_CONF="background_thread:true,dirty_decay_ms:1000,muzzy_decay_ms:1000"

# Profiling build
# ./configure --enable-prof
export MALLOC_CONF="prof:true,prof_active:true,lg_prof_sample:19"
```

jemalloc concepts:
- **Size classes** — rounded allocation sizes
- **tcache** — per-thread cache for hot sizes
- **arenas** — reduce contention across threads

```bash
# Statistics
export MALLOC_CONF="stats_print:true"
# prints on exit, or:
mallctl("epoch", ...); mallctl("stats.allocated", ...);
```

### 5. mimalloc

```bash
# Use mimalloc
LD_PRELOAD=/usr/lib/libmimalloc.so ./myapp

# Environment options
export MIMALLOC_SHOW_STATS=1
export MIMALLOC_PAGE_RESET=1
```

mimalloc hierarchy: segment → page → block. Generally lower metadata overhead than jemalloc.

```bash
# Statistics at exit
MIMALLOC_SHOW_STATS=1 ./myapp
```

### 6. tcmalloc thread-caching

```bash
LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libtcmalloc.so.4 ./myapp

# Environment
export TCMALLOC_SAMPLE_PARAMETER=524288  # sampling profiler
```

Per-thread caches for small objects; central heap for larger allocations.

### 7. Rust GlobalAlloc

```rust
use std::alloc::{GlobalAlloc, Layout, System};
use std::sync::atomic::{AtomicUsize, Ordering};

struct TrackingAllocator;

static ALLOCATED: AtomicUsize = AtomicUsize::new(0);

unsafe impl GlobalAlloc for TrackingAllocator {
    unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
        let ptr = System.alloc(layout);
        if !ptr.is_null() {
            ALLOCATED.fetch_add(layout.size(), Ordering::Relaxed);
        }
        ptr
    }
    unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
        System.dealloc(ptr, layout);
        ALLOCATED.fetch_sub(layout.size(), Ordering::Relaxed);
    }
}

#[global_allocator]
static GLOBAL: TrackingAllocator = TrackingAllocator;
```

For `#![no_std]` with `alloc` crate, implement `GlobalAlloc` without `System`.

### 8. Fragmentation metrics

| Type | Definition | Detection |
|------|------------|-----------|
| Internal | Allocated block larger than requested | Allocator stats; size class rounding |
| External | Free memory not usable for request | `mallinfo`/`malloc_info`; RSS vs heap |

```bash
# glibc malloc_info
malloc_info(0, stdout);

# jemalloc
jeprof --show_bytes ./myapp jeprof.heap
```

### 9. Benchmarking

```bash
# mimalloc bench (if built from source)
cd mimalloc && mkdir build && cd build
cmake .. && make
./mimalloc-bench

# Custom microbenchmark pattern
perf stat -e cycles,instructions ./allocator_bench --threads 8 --size 64
```

Compare: single-thread alloc/free, multi-thread contention, mixed size distribution.

## Common Problems

| Symptom | Cause | Fix |
|---------|-------|-----|
| Pool alloc returns NULL | Free list exhausted | Increase pool size; leak check |
| jemalloc RSS won't drop | Dirty page decay slow | Lower `dirty_decay_ms`; `madvise` |
| Arena OOM | No reset between phases | `arena_reset` or chain arenas |
| Rust allocator UB | Wrong Layout in dealloc | Store size/align with allocation |
| Worse perf with mimalloc | Wrong workload fit | Benchmark; try jemalloc |
| High external fragmentation | Long-lived mixed sizes | Segregate by lifetime; pools |

## Related Skills

- `skills/allocators/numa-programming` — NUMA-aware allocation
- `skills/rust/rust-no-std` — custom allocators in embedded Rust
- `skills/profilers/heaptrack` — allocation hotspot profiling
- `skills/profilers/valgrind` — heap leak detection
- `skills/low-level-programming/cpu-cache-opt` — allocator alignment and false sharing
- `skills/kernel/kernel-internals` — SLUB/buddy kernel allocators

© mohitmishra786 · MIT · mohitmishra786/low-level-dev-skills

Similar skills

All skills for Programming languages →

From the same set95

ebpf-rust Guidance for developing Linux eBPF programs in Rust via the Aya framework. It helps write kernel probes, stream events into Tokio, and fix verifier issues. CX Codex +1 438installs bazel Walks the agent through Bazel for C/C++ work: BUILD files, cc_library and cc_binary rules, toolchains, dependency graph queries. CX Codex +1 437installs stm32-baremetal Walks an agent through an STM32 firmware skeleton built on CMSIS headers alone: clock setup, RCC, linker script, arm-none-eabi-gcc build. CX Codex +1 360installs device-drivers A skill that walks the agent through Linux kernel driver work: platform, i2c and spi drivers, char devices, IRQ, DMA, regmap and runtime PM. CX Codex +1 358installs reverse-engineering A skill that walks the agent through binary analysis: Ghidra decompilation, radare2 workflows, Binary Ninja scripting. Useful when there is no source and you need the logic back. CX Codex +1 350installs abi-and-calling-conventions A skill that teaches your coding agent the ABI rules: which registers carry arguments, how the stack aligns, what breaks across FFI. CX Codex +1 342installs linux-kernel-architecture Gives your agent a map of the Linux kernel: boot sequence, major subsystems, initcall levels, and where code lives in linux.git. CX Codex +1 333installs memory-hierarchy-and-caches This skill guides agents through CPU cache levels, MESI coherence protocols, and false sharing diagnostics. It helps optimize data layouts when thread scaling drops. CX Codex +1 322installs

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor