Zig_allcator
Zig 语言不干预堆内存分配, 没有隐藏的内存分配,没有new关键字或其他任何使用堆分配器的语言功能,整个堆都是由库或者用户代码而非语言本身所管理的。
Zig 标准库提供了一中分配内存的模式,这允许程序员精准选择标准库中内存如何完成分配,在标准库中不会背着你偷偷分配内存。
Zig 提供的分配器 allocator 有:
- std.heap.page_allocator
- std.heap.FixedBufferAllocator
- std.heap.ArenaAllocator
- std.testing.allocator
- std.heap.c_allocator
释放内存惯用模式是使用defer。defer 在退出作用域时指定给定的代码,『作用域退出』包括到达作用域的结尾或从作用域返回。
Zig 的 defer 类似于 Go 的 defer,但存在一个主要区别。在 Zig 中,defer 将在其包含作用域的末尾运行。在 Go 中,defer 是在包含函数的末尾运行。
通过使用defer,指定分配器在退出作用域时释放分配的内存。
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
Section titled “std.heap.page_allocator”这是最基本的分配器,线程安全且无锁,每次内存的分配(allocation)和释放(free),都会触发一次直接的系统调用,它会直接要求操作系统分配或者释放整页内存, 即使是单直接内存分配也可能导致保留数千字节的内存。由于通过系统调用要求操作系统 OS 分配内存,这对于速读来说也是及其低效的。
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);}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_allocatorelse Allocator{ .ptr = undefined, .vtable = &PageAllocator.vtable, };std.heap.GeneralPurposeAllocator
Section titled “std.heap.GeneralPurposeAllocator”这是一种通用的、线程安全的分配器,可以作为程序的主分配器。这是一个安全的分配器,可以防止双重释放( double-free )、使用后释放( use-after-free)
还可以检测泄漏。可以通过它的配置结构(.{}),将安全检测和线程安全关闭掉:
test "GPA" { var gpa = std.heap.GeneralPurposeAllocator(.{}){}; const allocator = gpa.allocator();
const bytes = try allocator.alloc(u8, 100); defer allocator.free(bytes);}