← posts

メモリアロケータを自分で書いて学んだこと

はじめに

malloc はブラックボックスのままで困らない。けれど一度自分で書いてみると、「断片化」という言葉の手触りがまるで変わる。これは週末に mmap(2) から組んだ、素朴なアロケータの記録だ。

目的は速いアロケータを作ることではなく、確保と解放のあいだで何が起きているのかを、自分の手で一度なぞってみることだった。

最小の実装

まずは確保に失敗したら即座に死ぬ、薄いラッパから始める。エラー処理を呼び出し側にばら撒かないだけで、後の見通しが段違いに良くなる。

xmalloc.c
void *xmalloc(size_t n) {
    void *p = malloc(n);
    if (p == NULL) {
        perror("xmalloc");
        exit(1);
    }
    return p;
}

xmalloc は glibc の慣習にならった名前で、失敗時に NULL を返さず即死する。アロケータ本体を書くときも、この「失敗は即終了」という前提があると、確保まわりの分岐がぐっと減る。

落とし穴

アラインメントを忘れると、特定のアーキテクチャで突然死ぬ。境界に合わせて切り上げるだけの一行が、後から効いてくる。

返すポインタは、その領域に置きうるどんな型から見ても正しく整列している必要がある。bump アロケータなら、オフセットを進める前にサイズを境界へ切り上げておくだけでいい。

「速さは設計で決まり、正しさはテストで守られる」— と、深夜のセグフォルトが教えてくれた。

ベンチマーク

数字を見るまでは信じきれない。だからまず計測した。出力をそのまま貼る。

~/alloc $ ./bench --n 1e7
glibc  malloc :  412 ms
arena  bump   :  96 ms   (4.3x faster)
peak rss      :  128 MiB

確保と解放が一方向に偏るワークロードでは、arena の bump 確保が圧倒的に速い。汎用性を捨てた代わりに、分岐も free の管理コストもほとんど消えるからだ。mmap で大きな領域を一度だけ取り、その中を切り出していく構造が効いている。

まとめ

結局のところ、断片化と向き合うとは、アラインメントを意識し続けることだった。malloc はもう、私にとってブラックボックスではない。

#mmap

— fin. 2026-06-26
2-HOP LINKSこの記事と語をともにする記事
見出し = この記事が張ったリンク/その下 = 同じ語にリンクする別の記事