Arena Allocator em Zig — O que é e Como Usar

Arena Allocator em Zig — O que é e Como Usar

Definição

O Arena Allocator (std.heap.ArenaAllocator) em Zig é um alocador que agrupa múltiplas alocações e as libera todas de uma vez com uma única operação (deinit ou reset). Chamadas individuais a free são no-ops (não fazem nada). A arena obtém memória de um alocador “pai” (backing allocator) em blocos grandes e distribui fatias desses blocos.

É o alocador mais eficiente quando você tem um padrão de “alocar muita coisa, depois liberar tudo junto”.

Por que Arena Allocator Importa

  1. Performance: Alocação é quase instantânea (incrementa um ponteiro). Liberação é O(1).
  2. Simplicidade: Não precisa gerenciar free individual — deinit libera tudo.
  3. Sem fragmentação: Alocações são sequenciais dentro dos blocos.
  4. Padrão ideal para requisições: Aloca durante o processamento, libera ao final da requisição.

Exemplo Prático

Uso Básico

const std = @import("std");

pub fn main() !void {
    var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
    defer arena.deinit(); // Libera TODA a memória de uma vez

    const allocator = arena.allocator();

    // Todas essas alocações são rápidas
    const nome = try allocator.alloc(u8, 100);
    const dados = try allocator.alloc(u32, 500);
    const config = try allocator.create(Config);

    // Não precisa de free individual!
    // arena.deinit() cuida de tudo
    _ = nome;
    _ = dados;
    _ = config;
}

const Config = struct { porta: u16, debug: bool };

Padrão de Requisição HTTP

fn handleRequest(request: *Request, response: *Response) !void {
    // Arena para esta requisição
    var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
    defer arena.deinit(); // Tudo limpo ao final da requisição

    const alloc = arena.allocator();

    const body = try parseBody(alloc, request.body);
    const usuario = try buscarUsuario(alloc, body.user_id);
    const html = try renderTemplate(alloc, "perfil.html", usuario);

    try response.send(html);
    // Sem memory leak possível — arena libera tudo
}

Reset para Reutilização

fn processarLote(items: []const Item) !void {
    var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
    defer arena.deinit();

    for (items) |item| {
        // Reset mantém a memória alocada do SO, mas permite reutilizar
        _ = arena.reset(.retain_capacity);

        const alloc = arena.allocator();
        const resultado = try processarItem(alloc, item);
        try salvarResultado(resultado);
    }
}

Arena como Scratch Allocator

fn algoritmoComplexo(allocator: std.mem.Allocator) !Resultado {
    // Arena para alocações temporárias internas
    var scratch = std.heap.ArenaAllocator.init(allocator);
    defer scratch.deinit();

    const temp = scratch.allocator();

    // Muitas alocações temporárias durante o cálculo
    var intermediario = try temp.alloc(f64, 10000);
    _ = intermediario;
    var buffer = try temp.alloc(u8, 4096);
    _ = buffer;

    // Resultado final alocado com o allocator "real"
    const resultado = try allocator.create(Resultado);
    resultado.* = calcular();
    return resultado;
}

Quando Usar Arena

CenárioArena é boa?
Processamento de requisiçãoSim
Compilador/parser (por fase)Sim
Game loop (por frame)Sim
Estrutura de longa duraçãoNão (use GPA)
Alocações com lifetimes variadosNão

Armadilhas Comuns

  • Reter referências após deinit/reset: Qualquer ponteiro obtido da arena se torna inválido após deinit ou reset. Isso cria dangling pointers.
  • Arena que nunca é liberada: Em loops longos sem reset, a arena acumula memória indefinidamente.
  • Free individual não faz nada: Chamar free em uma alocação de arena não libera memória. Isso é por design.
  • Escolher o backing allocator errado: Use page_allocator para programas normais, ou outro allocator para contextos especiais.

Termos Relacionados

Tutoriais Relacionados

Continue aprendendo Zig

Explore mais tutoriais e artigos em português para dominar a linguagem Zig.