Zig Fixed Buffer Allocator
A fixed buffer allocator is an allocator that hands out memory from one fixed-size array. It never asks the system for more memory.
Serve from a buffer
Both slices come from one 64-byte array, in order.
const std = @import("std");
pub fn main() !void {
const out = std.io.getStdOut().writer();
var buf: [64]u8 = undefined;
var fba = std.heap.FixedBufferAllocator.init(&buf);
const alloc = fba.allocator();
const first = try alloc.alloc(u8, 8);
const second = try alloc.alloc(u8, 8);
try out.print("first={d} second={d}\n", .{ first.len, second.len });
}
A full buffer fails
The first slice fills the array, so the second allocation fails and is caught.
const std = @import("std");
pub fn main() !void {
const out = std.io.getStdOut().writer();
var buf: [32]u8 = undefined;
var fba = std.heap.FixedBufferAllocator.init(&buf);
const alloc = fba.allocator();
const first = try alloc.alloc(u8, 32);
try out.print("first={d}\n", .{first.len});
const second = alloc.alloc(u8, 8) catch null;
if (second == null) {
try out.print("second failed\n", .{});
} else {
try out.print("second ok\n", .{});
}
}
Reset and reuse
Reset marks the whole array free again, so a full-size slice fits a second time.
const std = @import("std");
pub fn main() !void {
const out = std.io.getStdOut().writer();
var buf: [16]u8 = undefined;
var fba = std.heap.FixedBufferAllocator.init(&buf);
const alloc = fba.allocator();
const a = try alloc.alloc(u8, 16);
try out.print("a={d}\n", .{a.len});
fba.reset();
const b = try alloc.alloc(u8, 16);
try out.print("b={d}\n", .{b.len});
}
Example
const std = @import("std");
pub fn main() !void {
const out = std.io.getStdOut().writer();
var buf: [64]u8 = undefined;
var fba = std.heap.FixedBufferAllocator.init(&buf);
const alloc = fba.allocator();
const hello = try std.fmt.allocPrint(alloc, "Hello, {s}!", .{"Zig"});
const bye = try std.fmt.allocPrint(alloc, "Bye, {s}!", .{"Zig"});
try out.print("{s} {s}\n", .{ hello, bye });
}
Key points
- FixedBufferAllocator: a fixed buffer allocator is an allocator that serves allocations from a single array given at creation.
- The array is an ordinary local variable, so its size is fixed when the program is written.
- Allocations come from the array in order, and each one takes the next free part.
- When the array is full, a new allocation fails instead of growing the array.
- A failed allocation can be caught with catch, and the program can carry on with what already fits.
- Reset: a reset is an operation that marks the whole array free again, so the buffer can be reused.
- This allocator fits short scratch work with a known size limit, like building one message.
The buffer holds both messages. No allocation asks the system for memory. The buffer itself needs no free call, since it is an ordinary local array.
Try it Yourself
Edit the code, then press Run.
Running is simulated
Exercise
What happens when a fixed buffer allocator runs out of room?