内存分配器 #
一、Allocator 接口 #
1.1 什么是 Allocator #
Zig 使用 Allocator 接口统一内存管理:
zig
const std = @import("std");
pub fn main() !void {
// 使用页面分配器
const allocator = std.heap.page_allocator;
// 分配内存
const buffer = try allocator.alloc(u8, 100);
defer allocator.free(buffer);
// 使用内存
for (buffer, 0..) |*b, i| {
b.* = @intCast(i % 256);
}
std.debug.print("Allocated {} bytes\n", .{buffer.len});
}
1.2 Allocator 方法 #
zig
const std = @import("std");
pub fn main() !void {
const allocator = std.heap.page_allocator;
// 分配切片
const slice = try allocator.alloc(i32, 10);
defer allocator.free(slice);
// 分配单个对象
const ptr = try allocator.create(i32);
defer allocator.destroy(ptr);
ptr.* = 42;
// 重新分配
var buffer = try allocator.alloc(u8, 10);
buffer = try allocator.realloc(buffer, 20);
defer allocator.free(buffer);
std.debug.print("ptr.* = {}\n", .{ptr.*});
std.debug.print("buffer.len = {}\n", .{buffer.len});
}
二、常用分配器 #
2.1 page_allocator #
最简单的分配器,直接向操作系统申请内存:
zig
const std = @import("std");
pub fn main() !void {
const allocator = std.heap.page_allocator;
const buffer = try allocator.alloc(u8, 4096);
defer allocator.free(buffer);
std.debug.print("Allocated {} bytes\n", .{buffer.len});
}
2.2 GeneralPurposeAllocator (GPA) #
通用分配器,支持内存泄漏检测:
zig
const std = @import("std");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
const buffer = try allocator.alloc(u8, 100);
defer allocator.free(buffer);
std.debug.print("Allocated {} bytes\n", .{buffer.len});
}
2.3 ArenaAllocator #
竞技场分配器,一次性释放所有内存:
zig
const std = @import("std");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
var arena = std.heap.ArenaAllocator.init(gpa.allocator());
defer arena.deinit();
const allocator = arena.allocator();
// 多次分配
const a = try allocator.alloc(u8, 100);
const b = try allocator.alloc(u8, 200);
const c = try allocator.alloc(u8, 300);
_ = a;
_ = b;
_ = c;
// 不需要单独释放,arena.deinit() 会一次性释放
std.debug.print("Arena allocations done\n", .{});
}
2.4 FixedBufferAllocator #
固定缓冲区分配器:
zig
const std = @import("std");
pub fn main() !void {
var buffer: [1024]u8 = undefined;
var fba = std.heap.FixedBufferAllocator.init(&buffer);
const allocator = fba.allocator();
const data = try allocator.alloc(u8, 100);
defer allocator.free(data);
std.debug.print("Allocated {} bytes from buffer\n", .{data.len});
}
三、分配与释放 #
3.1 alloc 和 free #
zig
const std = @import("std");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
// 分配切片
const numbers = try allocator.alloc(i32, 10);
defer allocator.free(numbers);
// 初始化
for (numbers, 0..) |*n, i| {
n.* = @intCast(i);
}
std.debug.print("numbers: {any}\n", .{numbers});
}
3.2 create 和 destroy #
zig
const std = @import("std");
const Node = struct {
value: i32,
next: ?*Node,
};
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
// 创建单个对象
const node = try allocator.create(Node);
defer allocator.destroy(node);
node.* = .{ .value = 42, .next = null };
std.debug.print("node.value = {}\n", .{node.value});
}
3.3 realloc #
zig
const std = @import("std");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
var buffer = try allocator.alloc(u8, 10);
// 扩展
buffer = try allocator.realloc(buffer, 20);
// 缩小
buffer = try allocator.realloc(buffer, 5);
defer allocator.free(buffer);
std.debug.print("buffer.len = {}\n", .{buffer.len});
}
四、内存泄漏检测 #
4.1 GPA 检测 #
zig
const std = @import("std");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer {
const leaked = gpa.deinit();
if (leaked == .leak) {
std.debug.print("Memory leak detected!\n", .{});
}
}
const allocator = gpa.allocator();
const buffer = try allocator.alloc(u8, 100);
defer allocator.free(buffer);
std.debug.print("No leaks here\n", .{});
}
五、实战示例 #
5.1 动态数组 #
zig
const std = @import("std");
fn DynamicArray(comptime T: type) type {
return struct {
items: []T,
len: usize,
allocator: std.mem.Allocator,
const Self = @This();
fn init(allocator: std.mem.Allocator) Self {
return .{
.items = &.{},
.len = 0,
.allocator = allocator,
};
}
fn deinit(self: *Self) void {
if (self.items.len > 0) {
self.allocator.free(self.items);
}
}
fn append(self: *Self, item: T) !void {
if (self.len >= self.items.len) {
const new_cap = if (self.items.len == 0) 4 else self.items.len * 2;
var new_items = try self.allocator.alloc(T, new_cap);
@memcpy(new_items[0..self.len], self.items[0..self.len]);
if (self.items.len > 0) {
self.allocator.free(self.items);
}
self.items = new_items;
}
self.items[self.len] = item;
self.len += 1;
}
fn get(self: Self, index: usize) ?T {
if (index >= self.len) return null;
return self.items[index];
}
};
}
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
var list = DynamicArray(i32).init(gpa.allocator());
defer list.deinit();
try list.append(1);
try list.append(2);
try list.append(3);
for (0..list.len) |i| {
std.debug.print("list[{}] = {}\n", .{ i, list.get(i).? });
}
}
六、总结 #
分配器要点:
| 分配器 | 用途 |
|---|---|
| page_allocator | 简单场景 |
| GPA | 通用场景,支持泄漏检测 |
| ArenaAllocator | 批量分配释放 |
| FixedBufferAllocator | 固定缓冲区 |
下一步,让我们学习高级特性!
最后更新:2026-03-27