Zig 语言不干预堆内存分配, 没有隐藏的内存分配,没有new关键字或其他任何使用堆分配器的语言功能,整个堆都是由库或者用户代码而非语言本身所管理的。

Zig 标准库提供了一中分配内存的模式,这允许程序员精准选择标准库中内存如何完成分配,在标准库中不会背着你偷偷分配内存。

Zig 提供的分配器 allocator 有:

defer

释放内存惯用模式是使用deferdefer 在退出作用域时指定给定的代码,『作用域退出』包括到达作用域的结尾或从作用域返回。

Zig 的 defer 类似于 Go 的 defer,但存在一个主要区别。在 Zig 中,defer 将在其包含作用域的末尾运行。在 Go 中,defer 是在包含函数的末尾运行。

通过使用defer,指定分配器在退出作用域时释放分配的内存。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
const allocator = gpa.allocator();

var arr = try allocator.alloc(usize, try getRandomCount());
defer allocator.free(arr);

for (0..arr.len) |i| {
	arr[i] = i;
}
std.debug.print("{any}\n", .{arr});

std.heap.page_allocator

这是最基本的分配器,线程安全且无锁,每次内存的分配(allocation)和释放(free),都会触发一次直接的系统调用,它会直接要求操作系统分配或者释放整页内存, 即使是单直接内存分配也可能导致保留数千字节的内存。由于通过系统调用要求操作系统 OS 分配内存,这对于速读来说也是及其低效的。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
const std = @import("std");
const expect = std.testing.expect;

test "allocation" {
    const allocator = std.heap.page_allocator;

    const memory = try allocator.alloc(u8, 100);
    defer allocator.free(memory);

    try expect(memory.len == 100);
    try expect(@TypeOf(memory) == []u8);
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
const page_allocator: type = if (builtin.target.isWasm())
    Allocator{
        .ptr = undefined,
        .vtable = &WasmPageAllocator.vtable,
    }
else if (builtin.target.os.tag == .plan9)
    Allocator{
        .ptr = undefined,
        .vtable = &SbrkAllocator(std.os.plan9.sbrk).vtable,
    }
else if (builtin.target.os.tag == .freestanding)
    root.os.heap.page_allocator
else
    Allocator{
        .ptr = undefined,
        .vtable = &PageAllocator.vtable,
    };

std.heap.GeneralPurposeAllocator

这是一种通用的、线程安全的分配器,可以作为程序的主分配器。这是一个安全的分配器,可以防止双重释放( double-free )、使用后释放( use-after-free) 还可以检测泄漏。可以通过它的配置结构(.{}),将安全检测和线程安全关闭掉:

1
2
3
4
5
6
7
test "GPA" {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    const allocator = gpa.allocator();

    const bytes = try allocator.alloc(u8, 100);
    defer allocator.free(bytes);
}

std.heap.FixedBufferAllocator

std.heap.ArenaAllocator

std.testing.allocator