🙄

ZigのAllocator まとめ

2022/11/05に公開約2,300字

ZigのAllocator まとめ

最近Zigに入門中。Allocatorについて調べたのでまとめる。

Allocators

Zigでは動的なメモリ管理のパターンが、標準ライブラリでいくつか提供されている。

std.heap.page_allocator

最も一般的なallocator。
OSにページ単位でメモリ要求する。最小単位がページのため、1byteのみ欲しい時など非効率な場合がある。

test "allocation" {
    // page_allocatorの生成
    const allocator = std.heap.page_allocator;

    // 100byteを確保
    const memory = try allocator.alloc(u8, 100);
    // スコープを出ると同時に確保した100byteを開放
    defer allocator.free(memory);

    try expect(memory.len == 100);
    try expect(@TypeOf(memory) == []u8);
}

std.heap.FixedBufferAllocator

固定長のメモリ割当を行う。ヒープ割当は行わないらしい。
カーネルを書く時など、ヒープ割当が望めない場合に利用できる。
実際の割当はコンパイル時に処理される?(スタック上に確保されるのか?)

test "fixed buffer allocator" {
    // キャパシティ情報だけ確保?
    var buffer: [1000]u8 = undefined;
    // ポインタを渡してallocatorを初期化
    var fba = std.heap.FixedBufferAllocator.init(&buffer);
    // FixedBufferAllocatorの生成
    const allocator = fba.allocator();

    // 100byteを確保
    const memory = try allocator.alloc(u8, 100);
    // スコープを出ると同時に確保した100byteを開放 (スタックに確保されるとするなら普通に開放される気がするが...)
    defer allocator.free(memory);

    try expect(memory.len == 100);
    try expect(@TypeOf(memory) == []u8);
}

std.heap.ArenaAllocator

複数回割当を実行できて、1回で開放できる。
開放するときはfreeじゃなくてdeinitらしい。
実際に割当を行うallocatorは別途指定する。

test "arena allocator" {
    // page_allocatorを指定してallocatorを初期化
    var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
    // スコープを抜けると同時に確保したメモリを一括開放
    defer arena.deinit();
    // ArenaAllAllocatorを生成
    const allocator = arena.allocator();

    // 複数回メモリを確保
    _ = try allocator.alloc(u8, 1);
    _ = try allocator.alloc(u8, 10);
    _ = try allocator.alloc(u8, 100);
}

std.heap.GeneralPurposeAllocator

複数回のfreeやメモリのリークなどが検知できる。

test "GPA" {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    // GeneralPurposeAllocatorを生成
    const allocator = gpa.allocator();
    defer {
        // 確保したメモリを開放 (2回目)
        const leaked = gpa.deinit();
	// 2重開放が戻り値で検知できる
        if (leaked) expect(false) catch @panic("TEST FAIL"); //fail test; can't try in defer as defer is executed after we return
    }
    
    // 100byteを確保
    const bytes = try allocator.alloc(u8, 100);
    // 確保したメモリを開放 (1回目)
    defer allocator.free(bytes);
}

std.heap.c_allocator

安全性は低いけどパフォーマンスが高いらしい。

Discussion

ログインするとコメントできます