3月2日、Joel Siks氏が「Why is my first C++ (m)allocation always 72 KB?」と題したブログ記事を公開し、話題を呼んでいる。この記事では、著者の特定の開発環境において、C++プログラムの実行直後に必ず発生していた「72 KB」というメモリ割り当ての要因について詳しく紹介されている。

以下に、その内容を紹介する。
観測された現象と調査
著者は自作のメモリアロケータ(mallocの実装)をテストする過程で、興味深い現象を報告している。Linux環境で LD_PRELOAD を用いて独自の malloc をロードさせたところ、どのようなプログラムであっても、最初の割り当てサイズが常に 73728バイト(72 KB) になっていたという。
$ head -n 1 log.txt
73728
gdbを用いたスタックトレースの解析の結果、この割り当てはプログラム本体の処理が始まる前、共有ライブラリである libstdc++ の初期化プロセスにおいて発生していることが特定された。
特定環境下での要因:エマージェンシー・プール
この72 KBの正体は、libstdc++ が管理する「エマージェンシー・プール(Emergency Pool)」である。
通常、C++の例外(exception)は malloc を使用してメモリを確保する。しかし、システム全体のメモリが枯渇した状況(Out of Memory)では、例外を投げるためのメモリ確保すら失敗するリスクがある。これに備え、libstdc++ は起動時にあらかじめ一定の領域を確保しておく設計となっている。
著者の環境で参照された libstdc++ のソースコード(eh_alloc.cc)では、以下のようにプールが初期化されている。
pool::pool() noexcept {
// ...
arena_size = buffer_size_in_bytes(obj_count, obj_size);
if (arena_size == 0)
return;
arena = (char *)malloc (arena_size);
if (!arena) {
// 割り当てに失敗した場合はエマージェンシー・プールなしで進行
arena_size = 0;
return;
}
// フリーリストの初期化
first_free_entry = reinterpret_cast <free_entry *> (arena);
new (first_free_entry) free_entry;
first_free_entry->size = arena_size;
first_free_entry->next = NULL;
}
なぜ「72 KB」なのか(環境依存性)
このサイズが「72 KB」となるのは、特定の計算式とシステムアーキテクチャに依存する結果である。プールのサイズは、例外オブジェクトの数(EMERGENCY_OBJ_COUNT)とサイズ(EMERGENCY_OBJ_SIZE)から算出されるが、これらはワードサイズ(64ビット等)の影響を受ける。
// libstdc++-v3/libsupc++/eh_alloc.cc より抜粋
#define EMERGENCY_OBJ_SIZE 6
#define EMERGENCY_OBJ_COUNT (4 * __SIZEOF_POINTER__ * __SIZEOF_POINTER__)
著者は、環境変数 GLIBCXX_TUNABLES を操作してオブジェクト数を変更することで、この初期割り当てサイズが連動して変化することを実験的に証明している。
$ GLIBCXX_TUNABLES=glibcxx.eh_pool.obj_count=10 \
LOG_ALLOC=log.txt \
LD_PRELOAD=./libmymalloc.so ls
$ head -n 1 log.txt
2880
留意すべき点
この記事が強調しているのは、この挙動が全ての環境で一律ではないということだ。以下の要因によって、割り当てサイズや挙動は変化する。
- 標準ライブラリの種類:
libstdc++ではなくlibc++を使用している場合。 - ビルド設定:
--enable-libstdcxx-static-eh-poolフラグを立ててビルドされたlibstdc++では、動的なmallocではなく静的バッファが使用される。 - プラットフォーム: OSやコンパイラ、ライブラリのバージョンによる実装の違い。
結論
著者が遭遇した「最初の72 KB」という謎は、C++がメモリ枯渇時でも安全に例外処理を継続するための防衛策が、特定のライブラリ構成において可視化したものであった。メモリデバッグツール(Valgrind等)で身に覚えのない割り当てが報告される場合、こうした標準ライブラリ内部のインフラストラクチャが関与している可能性がある。
詳細はWhy is the first C++ (m)allocation always 72 KB?を参照していただきたい。