Skip to main content

Manual Memory Management

Zig provides manual memory management without a garbage collector. You explicitly allocate and free memory using allocators.
Zig’s approach to memory management gives you full control while providing safety checks in Debug and ReleaseSafe modes.

Allocators

Allocators in Zig are represented by the std.mem.Allocator interface:
const std = @import("std");
const Allocator = std.mem.Allocator;
const expect = std.testing.expect;

test "using an allocator" {
    var buffer: [100]u8 = undefined;
    var fba = std.heap.FixedBufferAllocator.init(&buffer);
    const allocator = fba.allocator();
    const result = try concat(allocator, "foo", "bar");
    try expect(std.mem.eql(u8, "foobar", result));
}

fn concat(allocator: Allocator, a: []const u8, b: []const u8) ![]u8 {
    const result = try allocator.alloc(u8, a.len + b.len);
    @memcpy(result[0..a.len], a);
    @memcpy(result[a.len..], b);
    return result;
}
Passing allocators as parameters makes memory allocation explicit and testable.

Common Allocators

Page Allocator

Direct system memory allocator:
const allocator = std.heap.page_allocator;
const memory = try allocator.alloc(u8, 1024);
defer allocator.free(memory);

Arena Allocator

Allocates memory that’s freed all at once:
const std = @import("std");

pub fn main() !void {
    var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
    defer arena.deinit();

    const allocator = arena.allocator();

    const ptr = try allocator.create(i32);
    std.debug.print("ptr={}\n", .{ptr});
}
Arena allocators are perfect for request-scoped allocations where you want to free everything at once.

Fixed Buffer Allocator

Allocates from a fixed-size buffer:
var buffer: [1024]u8 = undefined;
var fba = std.heap.FixedBufferAllocator.init(&buffer);
const allocator = fba.allocator();

General Purpose Allocator

Detects memory leaks and use-after-free:
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
const allocator = std.heap.page_allocator;
// Simple, direct system allocator
// No tracking or safety checks

Allocator Interface

Allocating Memory

// Allocate a slice
const slice = try allocator.alloc(u8, 100);
defer allocator.free(slice);

// Allocate a single item
const item = try allocator.create(MyStruct);
defer allocator.destroy(item);

// Reallocate (resize)
const new_slice = try allocator.realloc(slice, 200);

Freeing Memory

// Free a slice
allocator.free(slice);

// Destroy a single item
allocator.destroy(item);
Always pair allocations with frees. Use defer to ensure cleanup happens even on error paths.

Memory Management Patterns

RAII with Defer

fn processData(allocator: Allocator) !void {
    const data = try allocator.alloc(u8, 1024);
    defer allocator.free(data);
    
    // Use data...
    // Automatically freed when function returns
}

Errdefer for Cleanup

fn createResource(allocator: Allocator) !*Resource {
    const resource = try allocator.create(Resource);
    errdefer allocator.destroy(resource);
    
    try resource.init();
    errdefer resource.deinit();
    
    try resource.configure();
    
    return resource;
}
Use errdefer to clean up resources only when an error occurs.

ArrayList

Dynamic arrays with automatic resizing:
const std = @import("std");

test "ArrayList" {
    var list = std.ArrayList(i32).init(std.testing.allocator);
    defer list.deinit();
    
    try list.append(1);
    try list.append(2);
    try list.append(3);
    
    try expect(list.items.len == 3);
    try expect(list.items[0] == 1);
}

HashMap

Hash maps for key-value storage:
test "HashMap" {
    var map = std.StringHashMap(i32).init(std.testing.allocator);
    defer map.deinit();
    
    try map.put("foo", 42);
    try map.put("bar", 100);
    
    try expect(map.get("foo").? == 42);
}

Stack vs Heap

fn stackExample() void {
    var array: [100]u8 = undefined;
    // Automatically freed when function returns
}

Memory Alignment

Control memory alignment for performance:
test "aligned allocation" {
    const allocator = std.testing.allocator;
    
    const aligned_ptr = try allocator.alignedAlloc(u8, 16, 64);
    defer allocator.free(aligned_ptr);
    
    try expect(@intFromPtr(aligned_ptr.ptr) % 16 == 0);
}

Memory Safety

Zig provides several safety features:

Undefined Behavior Detection

  • Use-after-free detection (with GPA)
  • Double-free detection
  • Memory leak detection
  • Bounds checking on slices

Build Modes

Full safety checks, slow execution, large binary
zig build

Ownership Patterns

Zig doesn’t enforce ownership rules at compile-time, but conventions exist:
const Resource = struct {
    data: []u8,
    allocator: Allocator,
    
    pub fn init(allocator: Allocator, size: usize) !Resource {
        return Resource{
            .data = try allocator.alloc(u8, size),
            .allocator = allocator,
        };
    }
    
    pub fn deinit(self: *Resource) void {
        self.allocator.free(self.data);
    }
};

test "resource management" {
    var resource = try Resource.init(std.testing.allocator, 100);
    defer resource.deinit();
    // Use resource...
}
Store the allocator in structs that manage their own memory for clean deinitialization.

Testing Allocator

Use the testing allocator to detect leaks in tests:
test "no leaks" {
    const allocator = std.testing.allocator;
    
    const data = try allocator.alloc(u8, 100);
    defer allocator.free(data);
    
    // Test will fail if we forget to free
}

Best Practices

  • Always use defer to pair allocations with frees
  • Use errdefer for cleanup on error paths
  • Pass allocators as function parameters
  • Use Arena allocators for temporary allocations
  • Use the testing allocator in tests to detect leaks
  • Store allocators in structs that manage memory
  • Prefer stack allocation when size is known and small
  • Use the General Purpose Allocator during development
Memory leaks won’t be detected at compile-time. Use the testing allocator and General Purpose Allocator to find them during development.

Build docs developers (and LLMs) love