mcpField
C
custom-allocators

custom-allocators

github.com/mohitmishra786开发269371 次安装18 周前更新
代码仓库

关于 custom-allocators

面向设计或调优内存分配器的开发者技能,介绍分配器类型,并涵盖 jemalloc、mimalloc、tcmalloc、C 池与 arena 模式、Rust GlobalAlloc、碎片指标和基准测试。

主要功能

  1. 01分配器类型与取舍
  2. 02jemalloc、mimalloc 和 tcmalloc 调优
  3. 03C 池与 arena 示例
  4. 04Rust GlobalAlloc 指南
  5. 05碎片指标与基准测试

适用场景

  1. 01调优服务器工作负载的分配器行为
  2. 02实现请求级 arena 或 C 内存池
  3. 03编写 Rust 自定义全局分配器
  4. 04调查内存碎片与分配性能

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/mohitmishra786/low-level-dev-skills --skill custom-allocators

安装后在 Claude Code 中输入/custom-allocators确认已加载。

详细介绍

自定义分配器

用途

指导 Agent 进行内存分配器设计与调优:内存池、slab、arena、buddy 分类,jemalloc 内部机制和 MALLOC_CONF,mimalloc 设计,tcmalloc 线程缓存,用 C 编写简单的内存池分配器,Rust GlobalAlloc trait,碎片指标以及基准测试。

适用场景

  • 为延迟敏感型或嵌入式工作负载替换 malloc
  • 调优 jemalloc/mimalloc,以适应服务端堆行为
  • 为请求作用域或基于帧的生命周期实现 arena 分配
  • 为 no_std 或性能需求编写 Rust 自定义全局分配器
  • 诊断堆碎片(内部碎片与外部碎片)
  • 对分配器吞吐量和延迟进行基准测试

工作流

1. 分配器分类
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. 用 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 分配器
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; }

在服务端使用按请求划分的 arena——响应后重置,无需逐个释放对象。

4. jemalloc 调优
# 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 概念:

  • 大小类别 — 经舍入后的分配大小
  • tcache — 用于常用大小的线程缓存
  • arenas — 降低线程间的争用
# Statistics
export MALLOC_CONF="stats_print:true"
# prints on exit, or:
mallctl("epoch", ...); mallctl("stats.allocated", ...);
5. mimalloc
# Use mimalloc
LD_PRELOAD=/usr/lib/libmimalloc.so ./myapp

# Environment options
export MIMALLOC_SHOW_STATS=1
export MIMALLOC_PAGE_RESET=1

mimalloc 层级:segment → page → block。通常比 jemalloc 的元数据开销更低。

# Statistics at exit
MIMALLOC_SHOW_STATS=1 ./myapp
6. tcmalloc 线程缓存
LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libtcmalloc.so.4 ./myapp

# Environment
export TCMALLOC_SAMPLE_PARAMETER=524288  # sampling profiler

小对象使用线程本地缓存;较大的分配使用中央堆。

7. Rust GlobalAlloc
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;

对于使用 alloc crate 的 #![no_std],无需 System 即可实现 GlobalAlloc。

8. 碎片指标
类型定义检测方式
内部碎片已分配块大于请求大小分配器统计信息;大小类别舍入
外部碎片空闲内存无法满足请求mallinfo/malloc_info;RSS 与堆
# glibc malloc_info
malloc_info(0, stdout);

# jemalloc
jeprof --show_bytes ./myapp jeprof.heap
9. 基准测试
# 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

比较内容:单线程分配/释放、多线程争用、混合大小分布。

常见问题

症状原因解决方法
内存池分配返回 NULL空闲链表耗尽增大内存池;检查内存泄漏
jemalloc RSS 不下降脏页衰减缓慢降低 dirty_decay_ms;使用 madvise
Arena 内存不足阶段之间未重置使用 arena_reset 或链接多个 arena
Rust 分配器出现未定义行为释放时的 Layout 错误随分配结果保存大小/对齐方式
使用 mimalloc 时性能更差与工作负载不匹配进行基准测试;尝试 jemalloc
外部碎片严重长生命周期对象大小混杂按生命周期隔离;使用内存池

相关技能

  • skills/allocators/numa-programming — NUMA 感知型分配
  • skills/rust/rust-no-std — 嵌入式 Rust 中的自定义分配器
  • skills/profilers/heaptrack — 分配热点分析
  • skills/profilers/valgrind — 堆内存泄漏检测
  • skills/low-level-programming/cpu-cache-opt — 分配器对齐和伪共享
  • skills/kernel/kernel-internals — SLUB/buddy 内核分配器

评论

支持 Markdown