Skip to content

x 前缀的内存分配包装器 —— 分配失败时直接退出程序,省去每个调用点重复的 NULL 检查。

为什么需要 xmalloc

C 语言的 malloc 失败时返回 NULL,理论上每次调用都要检查:

c
// 没有 xwrapper 时:
void *p = malloc(size);
if (p == NULL) {
    fprintf(stderr, "out of memory\n");
    exit(1);
}
// ... 每次调用都要重复这三行

ds4.c 有几百处内存分配,重复的 NULL 检查让代码膨胀且容易遗漏。xmalloc 把错误处理集中到一处,调用点只写 p = xmalloc(size)

核心原理

xmalloc(size)  → malloc(size)  + NULL → fprintf + exit(1)
xcalloc(n, s)  → calloc(n, s) + NULL → fprintf + exit(1)
xrealloc(p, s) → realloc(p,s) + NULL → fprintf + exit(1)

为什么没有 xfree?释放 NULL 是安全的(free(NULL) 是 no-op),不需要包装。

在 ds4.c 中的实现

c
// ds4.c — xwrapper 家族
void *xmalloc(size_t size) {
    void *p = malloc(size);
    if (!p) { fprintf(stderr, "xmalloc: out of memory\n"); exit(1); }
    return p;
}

特别注意 xmalloc_zeroed

c
void *xmalloc_zeroed(size_t size) {
    void *p = xmalloc(size);
    memset(p, 0, size);   // 手动清零
    return p;
}

为什么不用 xcalloc?Darwin 内核对大块 calloc 使用共享零页(CoW zero page)——物理内存只在首次写入时分配。这把大量 page fault 延迟到推理阶段,在 macOS 上可能导致内核 panic。malloc + memset 立即触发所有 page fault,在启动阶段集中处理。

相关概念

  • page-fault — xmalloc_zeroed 避免 calloc 的延迟 page fault 陷阱
  • mmap — 模型数据通过 mmap 零拷贝加载,不经过 xmalloc

详见 Part 1 — 内存管理与 mmap