# General-Purpose Allocator

### General-Purpose Allocator

The general-purpose allocator is used for ordinary heap allocation.

It is designed for programs that allocate and free many objects of different sizes.

A typical program sets it up near `main`:

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

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

    const allocator = gpa.allocator();

    const bytes = try allocator.alloc(u8, 128);
    defer allocator.free(bytes);

    @memset(bytes, 0);

    std.debug.print("allocated {d} bytes\n", .{bytes.len});
}
```

The value `gpa` is the allocator state. The value `allocator` is the allocator interface used by the rest of the program.

```zig
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
const allocator = gpa.allocator();
```

The state must live as long as any memory allocated from it. Do not return an allocator whose backing state has gone out of scope.

This is wrong:

```zig
fn makeAllocator() std.mem.Allocator {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    return gpa.allocator(); // wrong
}
```

The returned allocator refers to `gpa`, but `gpa` is destroyed when the function returns.

The allocator value is small, but it is not the whole allocator. It points to allocator state.

The general-purpose allocator must be deinitialized:

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

The call releases internal state and may report leaks, depending on configuration and build mode. In examples, the return value is often ignored with `_ =`.

For reusable code, pass the allocator down:

```zig
fn work(allocator: std.mem.Allocator) !void {
    const names = try allocator.alloc([]const u8, 4);
    defer allocator.free(names);

    names[0] = "zig";
    names[1] = "c";
    names[2] = "go";
    names[3] = "rust";
}
```

The function does not know whether the caller used a general-purpose allocator, an arena, a fixed buffer, or a testing allocator.

That is the point.

The general-purpose allocator is a good default for applications. It is less suitable for short-lived batches of objects that all die at the same time. For that, an arena is often simpler.

Compare these two cases.

First, mixed lifetimes:

```zig
const user = try allocator.create(User);
defer allocator.destroy(user);

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

The objects may be created and destroyed at different times. A general-purpose allocator fits this pattern.

Second, one shared lifetime:

```zig
const tokens = try allocator.alloc(Token, token_count);
const nodes = try allocator.alloc(Node, node_count);
const names = try allocator.alloc([]const u8, name_count);
```

If all of these are temporary parser data and will be freed together, an arena may fit better.

The general-purpose allocator gives flexibility. It also requires exact cleanup. Each allocation must be paired with the correct release operation.

Use:

```zig
allocator.free(slice);
```

for memory returned by `alloc`.

Use:

```zig
allocator.destroy(pointer);
```

for memory returned by `create`.

A common application shape is:

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

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

    try run(gpa.allocator());
}

fn run(allocator: std.mem.Allocator) !void {
    var list = std.ArrayList(u8).init(allocator);
    defer list.deinit();

    try list.appendSlice("hello");
    try list.append(' ');
    try list.appendSlice("zig");

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

`main` chooses the allocator. `run` receives it. The rest of the program uses it explicitly.

This pattern keeps allocation policy at the edge of the program and allocation use inside the program.

Exercises:

Exercise 12-9. Create a general-purpose allocator in `main`, allocate 256 bytes, fill them with `1`, and free them.

Exercise 12-10. Write a `run` function that receives `std.mem.Allocator` and builds an `ArrayList(u32)`.

Exercise 12-11. Write a program that allocates one `Point` struct with `create`, sets its fields, prints them, and destroys it.

Exercise 12-12. Explain why returning `gpa.allocator()` from a function with a local `gpa` is invalid.

