---
title: "Cheatsheet: Allocators em Zig"
url: "https://ziglang.com.br/cheatsheets/cheatsheet-allocators-em-zig/"
markdown_url: "https://ziglang.com.br/cheatsheets/cheatsheet-allocators-em-zig.MD"
description: "Referência rápida para alocadores de memória em Zig: GeneralPurposeAllocator, ArenaAllocator, FixedBufferAllocator, page_allocator e padrões de alocação. Guia completo em português."
date: "2026-02-21"
author: "Zig Brasil"
---

# Cheatsheet: Allocators em Zig

Referência rápida para alocadores de memória em Zig: GeneralPurposeAllocator, ArenaAllocator, FixedBufferAllocator, page_allocator e padrões de alocação. Guia completo em português.


# Cheatsheet: Allocators em Zig

O sistema de alocadores é um dos pilares fundamentais de Zig. Em vez de um alocador global implícito como em C (`malloc`/`free`) ou um garbage collector como em Go/Java, Zig exige que você passe **explicitamente** um alocador para qualquer função que precise alocar memória. Isso dá controle total e facilita testes, depuração e otimização.

## Conceito Fundamental

Em Zig, `std.mem.Allocator` é uma **interface** (implementada via ponteiro de função). Qualquer código que precisa alocar memória recebe um `Allocator` como parâmetro:

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

fn criarLista(allocator: std.mem.Allocator) !std.ArrayList(u8) {
    return std.ArrayList(u8).init(allocator);
}
```

**Por que isso importa:**
- Sem estado global oculto — cada alocação é explícita
- Fácil trocar alocadores para testes ou otimização
- Detecção automática de vazamento de memória em modo debug
- Permite alocadores especializados para cada caso de uso

## Tipos de Alocadores

### GeneralPurposeAllocator (GPA)

O alocador mais usado no dia a dia. Detecta vazamentos de memória e uso indevido (use-after-free, double-free) em modo debug.

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

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer {
        const status = gpa.deinit();
        if (status == .leak) @panic("Vazamento de memória detectado!");
    }
    const allocator = gpa.allocator();

    // Usar o allocator normalmente
    const dados = try allocator.alloc(u8, 100);
    defer allocator.free(dados);

    // Alocar um único item
    const ptr = try allocator.create(u32);
    defer allocator.destroy(ptr);
    ptr.* = 42;
}
```

**Opções de configuração:**

```zig
var gpa = std.heap.GeneralPurposeAllocator(.{
    .stack_trace_frames = 8,       // frames no stack trace de erros
    .enable_memory_limit = true,   // habilitar limite de memória
    .thread_safe = true,           // seguro para múltiplas threads
}){};
gpa.setRequestedMemoryLimit(1024 * 1024); // limite de 1MB
```

### ArenaAllocator

Aloca tudo de uma vez e libera tudo junto. Excelente para operações com tempo de vida bem definido.

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

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

    // Arena usa outro alocador como backend
    var arena = std.heap.ArenaAllocator.init(gpa.allocator());
    defer arena.deinit(); // libera TUDO de uma vez

    const allocator = arena.allocator();

    // Não precisa de free individual!
    const buf1 = try allocator.alloc(u8, 256);
    const buf2 = try allocator.alloc(u8, 512);
    const buf3 = try allocator.alloc(u8, 1024);

    // Usar buf1, buf2, buf3...
    _ = buf1;
    _ = buf2;
    _ = buf3;

    // Resetar arena sem liberar a memória do SO
    _ = arena.reset(.retain_capacity);
    // Agora a memória pode ser reutilizada
}
```

**Quando usar Arena:**
- Processamento de requisições (alocar tudo, processar, liberar tudo)
- Parsing de dados temporários
- Operações batch que produzem resultado final

### FixedBufferAllocator

Aloca memória a partir de um buffer fixo na stack ou pré-alocado. Zero alocações no heap.

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

pub fn main() !void {
    var buffer: [4096]u8 = undefined;
    var fba = std.heap.FixedBufferAllocator.init(&buffer);
    const allocator = fba.allocator();

    // Aloca do buffer estático
    const dados = try allocator.alloc(u8, 100);
    _ = dados;

    // Se ultrapassar 4096 bytes, retorna error.OutOfMemory
    // Resetar para reusar
    fba.reset();
}
```

**Quando usar FixedBuffer:**
- Sistemas embarcados sem heap
- Operações com tamanho máximo conhecido
- Quando não pode falhar na alocação (pré-aloca tudo)

### page_allocator

Alocador que usa diretamente as chamadas de sistema do SO (`mmap`/`VirtualAlloc`). Cada alocação pede pelo menos uma página (geralmente 4KB).

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

pub fn main() !void {
    const allocator = std.heap.page_allocator;

    // Cada alocação é no mínimo uma página do SO
    const dados = try allocator.alloc(u8, 1024);
    defer allocator.free(dados);

    // Bom para alocações grandes
    const grande = try allocator.alloc(u8, 1024 * 1024); // 1MB
    defer allocator.free(grande);
}
```

### c_allocator

Wrapper sobre `malloc`/`free` do C. Útil para interop com bibliotecas C.

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

pub fn main() !void {
    const allocator = std.heap.c_allocator;

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

**Nota:** Requer linkagem com libc (`-lc` ou `const std_options = .{ .link_libc = true }` no `build.zig`).

## Operações do Allocator

### Tabela de Referência Rápida

| Operação | Descrição | Exemplo |
|----------|-----------|---------|
| `alloc(T, n)` | Alocar array de n elementos | `try alloc.alloc(u8, 100)` |
| `free(slice)` | Liberar slice alocado | `alloc.free(dados)` |
| `create(T)` | Alocar um único item | `try alloc.create(Struct)` |
| `destroy(ptr)` | Liberar item único | `alloc.destroy(ptr)` |
| `realloc(slice, n)` | Redimensionar alocação | `try alloc.realloc(buf, 200)` |
| `dupe(T, slice)` | Duplicar slice | `try alloc.dupe(u8, "cópia")` |

### Exemplos Detalhados

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

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

    // alloc e free
    const nums = try alloc.alloc(i32, 10);
    defer alloc.free(nums);
    for (nums, 0..) |*n, i| {
        n.* = @intCast(i);
    }

    // create e destroy
    const Ponto = struct { x: f32, y: f32 };
    const p = try alloc.create(Ponto);
    defer alloc.destroy(p);
    p.* = .{ .x = 1.0, .y = 2.0 };

    // dupe — cria cópia independente
    const original = "texto original";
    const copia = try alloc.dupe(u8, original);
    defer alloc.free(copia);

    // realloc — redimensionar
    var buf = try alloc.alloc(u8, 10);
    buf = try alloc.realloc(buf, 50); // agora tem 50 bytes
    defer alloc.free(buf);
}
```

## Padrão: Alocador como Parâmetro

A convenção em Zig é sempre receber o alocador como parâmetro:

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

const MeuBuffer = struct {
    dados: []u8,
    allocator: std.mem.Allocator,

    pub fn init(allocator: std.mem.Allocator, tamanho: usize) !MeuBuffer {
        return .{
            .dados = try allocator.alloc(u8, tamanho),
            .allocator = allocator,
        };
    }

    pub fn deinit(self: *MeuBuffer) void {
        self.allocator.free(self.dados);
    }
};
```

## Padrão: Defer para Limpeza

Sempre use `defer` para garantir a liberação:

```zig
fn processarDados(allocator: std.mem.Allocator) ![]u8 {
    var temp = try allocator.alloc(u8, 1024);
    defer allocator.free(temp); // liberado mesmo se houver erro

    // ... processar usando temp ...

    // Resultado separado que será retornado (caller faz free)
    const resultado = try allocator.dupe(u8, temp[0..tamanho_real]);
    return resultado;
}
```

## Comparativo dos Alocadores

| Alocador | Velocidade | Segurança Debug | Uso Ideal |
|----------|-----------|-----------------|-----------|
| `GeneralPurposeAllocator` | Médio | Alta (detecta leaks) | Desenvolvimento geral |
| `ArenaAllocator` | Rápido | Média | Operações batch |
| `FixedBufferAllocator` | Muito rápido | Baixa | Embarcados, stack |
| `page_allocator` | Lento | Nenhuma | Alocações grandes |
| `c_allocator` | Médio | Nenhuma | Interop com C |

## Erros Comuns

```zig
// ERRO: esquecer de liberar memória
fn ruim(allocator: std.mem.Allocator) !void {
    const dados = try allocator.alloc(u8, 100);
    // Sem free! GPA vai detectar o vazamento
}

// CORRETO: usar defer
fn bom(allocator: std.mem.Allocator) !void {
    const dados = try allocator.alloc(u8, 100);
    defer allocator.free(dados);
    // ...
}

// ERRO: usar memória após free (use-after-free)
fn perigoso(allocator: std.mem.Allocator) !void {
    const dados = try allocator.alloc(u8, 100);
    allocator.free(dados);
    dados[0] = 42; // Comportamento indefinido!
}
```

O sistema de allocators explícitos de Zig é único entre as linguagens de sistemas modernas. Para entender as alternativas, <a href="https://rustlang.com.br/artigos/rust-ownership-borrowing/" target="_blank" rel="noopener" onclick="umami.track('portfolio-site-click', { destination: 'rustlang.com.br' })">Rust utiliza ownership e borrowing para gerenciar memória em tempo de compilação</a>, enquanto <a href="https://golang.com.br/artigos/go-garbage-collector/" target="_blank" rel="noopener" onclick="umami.track('portfolio-site-click', { destination: 'golang.com.br' })">Go conta com um garbage collector de baixa latência</a>.

## Veja Também

- [Error Handling](/cheatsheets/error-handling/) — Tratamento de erros com allocators
- [Structs](/cheatsheets/structs/) — Structs que gerenciam memória
- [Arena Pattern](/padroes/arena-pattern/) — Padrão de uso avançado de arenas
- [Troubleshooting: Memory Leak](/troubleshooting/zig-memory-leak-encontrar/) — Como encontrar vazamentos
- [std.mem na Biblioteca Padrão](/stdlib/) — Documentação completa de std.mem
