zig-alloc - 背景
歴史的経緯
メモリアロケータの進化
- 初期のアロケータ(1960年代)
- Buddy System(1963年)
- Slab Allocator(1994年)
- jemalloc(2005年)
Zigのアロケータ設計
Zigは独自のアプローチを採用:
// アロケータは明示的に渡される
fn processData(allocator: std.mem.Allocator, data: []const u8) ![]u8 {
const result = try allocator.alloc(u8, data.len);
// ...
return result;
}
コンピュータサイエンス的な意味
アロケーション戦略
| 戦略 | 特徴 | 用途 |
|---|---|---|
| First Fit | シンプル、断片化しやすい | 汎用 |
| Best Fit | 断片化を抑制、遅い | 長期実行 |
| Worst Fit | 大きな空き領域を維持 | 可変サイズ |
| Next Fit | First Fitの改良 | 汎用 |
メモリ断片化
外部フラグメンテーション:
[使用中][空き][使用中][空き][使用中]
↓
合計空き容量は十分だが、連続した領域がない
内部フラグメンテーション:
[要求: 100B][割当: 128B] → 28B の無駄
アロケータの階層
アプリケーション
↓
カスタムアロケータ(プール、アリーナ)
↓
汎用アロケータ(malloc)
↓
システムアロケータ(mmap, VirtualAlloc)
↓
カーネル(ページアロケータ)
実践での活用
ゲーム開発
// フレームアロケータ - 毎フレームリセット
var frame_arena = ArenaAllocator.init(page_allocator);
defer frame_arena.deinit();
while (game_running) {
// フレーム内のアロケーションは全てアリーナから
processFrame(frame_arena.allocator());
// フレーム終了時に一括解放
frame_arena.reset();
}
組み込みシステム
// 静的バッファのみ使用(ヒープなし)
var static_buffer: [64 * 1024]u8 = undefined;
var fba = FixedBufferAllocator.init(&static_buffer);
// このアロケータは追加のメモリ要求をしない
高性能サーバー
// リクエストごとにアリーナを使用
fn handleRequest(req: *Request) !void {
var arena = ArenaAllocator.init(gpa);
defer arena.deinit();
// リクエスト処理中の全てのアロケーション
const response = try processRequest(arena.allocator(), req);
try sendResponse(response);
// 関数終了時に全て解放
}
実世界とのギャップ
Zigの明示的アロケータ vs 他言語
| 言語 | アロケーション方法 |
|---|---|
| C | malloc/free(暗黙的) |
| C++ | new/delete、アロケータ |
| Rust | Box、Vec(暗黙的) |
| Go | GC(完全自動) |
| Zig | 明示的アロケータ渡し |
利点と欠点
利点:
- メモリ使用パターンが明確
- 最適なアロケータを選択可能
- テスト時にモックアロケータ使用可能
欠点:
- コードが冗長になりがち
- アロケータの伝播が必要
- 学習曲線が急