# General Purpose Allocator

### General Purpose Allocator

The general purpose allocator is Zig’s standard allocator for ordinary heap allocation.

Use it when your program needs heap memory, but you do not need a special strategy yet.

It can allocate memory of different sizes, free memory in any order, and help detect memory mistakes during development.

A small program usually starts like this:

```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, 1024);
    defer allocator.free(buffer);

    buffer[0] = 42;
}
```

The important lines are these:

```zig
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();

const allocator = gpa.allocator();
```

`gpa` is the allocator object. It owns the internal state needed to manage memory.

`gpa.allocator()` gives you a `std.mem.Allocator` value. That is the interface you pass to functions.

This distinction matters:

```text
GeneralPurposeAllocator is the implementation.
std.mem.Allocator is the interface.
```

Many Zig functions do not care which allocator implementation you use. They only need the allocator interface.

#### Why Use It

The general purpose allocator is useful because it behaves like the heap allocator many programmers expect.

You can allocate one buffer:

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

You can allocate many buffers:

```zig
const a = try allocator.alloc(u8, 100);
defer allocator.free(a);

const b = try allocator.alloc(u8, 500);
defer allocator.free(b);

const c = try allocator.alloc(u8, 20);
defer allocator.free(c);
```

You can free them in a different order from the order you allocated them.

That makes it flexible.

This flexibility costs more than a simple arena or fixed buffer allocator, but it is a good default while learning.

#### Detecting Leaks

One major reason to use the general purpose allocator during development is leak detection.

Look at this program:

```zig
const std = @import("std");

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();

    const allocator = gpa.allocator();

    _ = try allocator.alloc(u8, 1024);
}
```

This allocates memory but never frees it.

A careful program should do this instead:

```zig
const buffer = try allocator.alloc(u8, 1024);
defer allocator.free(buffer);
```

When `gpa.deinit()` runs, the allocator can report that memory was leaked.

For beginner code, this is useful. It gives you feedback when you forget cleanup.

#### Checking `deinit`

You will often see this form:

```zig
defer {
    const result = gpa.deinit();
    if (result == .leak) {
        std.debug.print("memory leak detected\n", .{});
    }
}
```

This checks whether the allocator found leaked memory.

A shorter version is common in examples:

```zig
defer _ = gpa.deinit();
```

The short version ignores the result. That is acceptable for small examples, but in real debugging code, checking the result is better.

#### Passing the Allocator to Functions

A common pattern is to create the allocator once near the top of your program, then pass it into functions that need memory.

```zig
const std = @import("std");

fn makeMessage(allocator: std.mem.Allocator) ![]u8 {
    return try std.fmt.allocPrint(allocator, "hello {s}", .{"zig"});
}

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();

    const allocator = gpa.allocator();

    const message = try makeMessage(allocator);
    defer allocator.free(message);

    std.debug.print("{s}\n", .{message});
}
```

The function `makeMessage` receives an allocator because it creates a new string.

The caller frees the returned string because the caller owns it.

This is the normal Zig ownership pattern:

```text
The function allocates.
The function returns owned memory.
The caller frees it.
```

#### Allocator Lifetime

The allocator must live longer than the memory it gives out.

This is correct:

```zig
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();

const allocator = gpa.allocator();

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

The allocator is created first. The buffer is freed before `gpa.deinit()` runs.

This would be wrong in spirit:

```zig
const buffer = try allocator.alloc(u8, 100);
defer _ = gpa.deinit();
defer allocator.free(buffer);
```

Because `defer` runs in reverse order, this would free the buffer after deinitializing the allocator. That is not the order you want.

Use this order:

```zig
defer _ = gpa.deinit();

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

The later `defer` runs first, so the buffer is freed before the allocator is deinitialized.

#### Good Beginner Pattern

For early programs, use this structure:

```zig
const std = @import("std");

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer {
        const status = gpa.deinit();
        if (status == .leak) {
            std.debug.print("memory leak detected\n", .{});
        }
    }

    const allocator = gpa.allocator();

    // pass allocator to code that needs heap memory
    const items = try allocator.alloc(i32, 10);
    defer allocator.free(items);

    items[0] = 123;
}
```

This gives you a real heap allocator and a basic leak check.

#### When to Use Something Else

The general purpose allocator is a good default, but it is not always the best allocator.

Use an arena allocator when many allocations have the same lifetime and can be freed together.

Use a fixed buffer allocator when you want all allocation to come from a fixed block of memory.

Use the page allocator when you need direct page-level allocation or a simple backing allocator for another allocator.

The general purpose allocator is flexible. Specialized allocators are often simpler or faster for specific memory patterns.

#### The Core Idea

The general purpose allocator is the allocator you reach for when you need normal heap behavior.

It is useful while learning because it supports flexible allocation and helps expose leaks.

The main rule stays the same:

```text
Every allocation needs a matching cleanup plan.
```

