---
title: "Allocator Leak Detected — Como Resolver em Zig"
url: "https://ziglang.com.br/erros/allocator-leak-detected-como-resolver-em-zig/"
markdown_url: "https://ziglang.com.br/erros/allocator-leak-detected-como-resolver-em-zig.MD"
description: "Entenda o aviso de vazamento de memória detectado pelo GeneralPurposeAllocator em Zig. Veja como rastrear e corrigir leaks no seu código."
date: "2026-02-21"
author: "Zig Brasil"
---

# Allocator Leak Detected — Como Resolver em Zig

Entenda o aviso de vazamento de memória detectado pelo GeneralPurposeAllocator em Zig. Veja como rastrear e corrigir leaks no seu código.


# Allocator Leak Detected — Como Resolver em Zig

## O Que Este Erro Significa

O aviso "leak detected" é emitido pelo `GeneralPurposeAllocator` (GPA) quando seu método `deinit()` é chamado e ainda existem alocações que nunca foram liberadas. Diferente de um crash, este é um diagnóstico que o GPA fornece para ajudar a encontrar e corrigir vazamentos de memória durante o desenvolvimento.

A saída típica:

```
error(gpa): memory address 0x7f5a12340000 leaked
error(gpa): leaked allocation of 1024 bytes at src/main.zig:15
```

O GPA rastreia cada alocação e seu stack trace de origem, fornecendo informação precisa sobre onde a memória foi alocada mas nunca liberada.

## Causas Comuns

### 1. Esquecer de Chamar deinit em Coleções

```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("LEAK!\n", .{});
    }
    const allocator = gpa.allocator();

    var lista = std.ArrayList(u32).init(allocator);
    try lista.append(1);
    try lista.append(2);
    // LEAK: nunca chamou lista.deinit()
}
```

### 2. Retorno Antecipado sem Cleanup

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

fn processar(allocator: std.mem.Allocator) !void {
    const buf = try allocator.alloc(u8, 1024);

    if (true) { // Alguma condição
        return error.Falha; // LEAK: buf não foi liberado!
    }

    allocator.free(buf);
}
```

### 3. HashMap/ArrayHashMap sem deinit

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

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

    var mapa = std.StringHashMap(u32).init(allocator);
    try mapa.put("chave", 42);
    // LEAK: mapa.deinit() nunca chamado
}
```

### 4. Esquecer de Liberar Valores dentro de Coleções

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

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

    var lista = std.ArrayList([]u8).init(allocator);
    defer lista.deinit(); // Libera a lista, mas NÃO os itens

    try lista.append(try allocator.alloc(u8, 100)); // Item 1
    try lista.append(try allocator.alloc(u8, 200)); // Item 2
    // LEAK: os itens individuais nunca são liberados
}
```

### 5. Erro em Cadeia de Alocações

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

fn criarRecurso(allocator: std.mem.Allocator) !void {
    const a = try allocator.alloc(u8, 100);
    const b = try allocator.alloc(u8, 200); // Se falhar, 'a' vaza
    const c = try allocator.alloc(u8, 300); // Se falhar, 'a' e 'b' vazam

    allocator.free(c);
    allocator.free(b);
    allocator.free(a);
}
```

## Como Corrigir

### Solucao 1: defer e errdefer para Cada Alocação

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

fn criarRecurso(allocator: std.mem.Allocator) !void {
    const a = try allocator.alloc(u8, 100);
    errdefer allocator.free(a);

    const b = try allocator.alloc(u8, 200);
    errdefer allocator.free(b);

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

    // Processamento...
    defer allocator.free(b);
    defer allocator.free(a);
}
```

### Solucao 2: Limpar Coleções com Dados Aninhados

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

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

    var lista = std.ArrayList([]u8).init(allocator);
    defer {
        // Libera cada item ANTES de liberar a lista
        for (lista.items) |item| {
            allocator.free(item);
        }
        lista.deinit();
    }

    try lista.append(try allocator.alloc(u8, 100));
    try lista.append(try allocator.alloc(u8, 200));
}
```

### Solucao 3: Sempre Chamar deinit em Structs com Estado

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

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

    var mapa = std.StringHashMap(u32).init(allocator);
    defer mapa.deinit();

    var lista = std.ArrayList(u8).init(allocator);
    defer lista.deinit();

    var buf_writer = std.ArrayList(u8).init(allocator);
    defer buf_writer.deinit();
}
```

### Solucao 4: ArenaAllocator para Ciclo de Vida Compartilhado

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

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

    var arena = std.heap.ArenaAllocator.init(gpa.allocator());
    defer arena.deinit(); // Libera ABSOLUTAMENTE tudo — zero leaks possíveis

    const allocator = arena.allocator();

    var lista = std.ArrayList([]u8).init(allocator);
    // Sem defer lista.deinit() necessário — arena cuida

    try lista.append(try allocator.alloc(u8, 100));
    try lista.append(try allocator.alloc(u8, 200));
    // Sem free individual necessário — arena cuida
}
```

### Solucao 5: Verificar Leaks em Testes

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

test "sem vazamento de memória" {
    // testing.allocator detecta leaks automaticamente
    const allocator = std.testing.allocator;

    var lista = std.ArrayList(u32).init(allocator);
    defer lista.deinit();

    try lista.append(42);
    try std.testing.expectEqual(@as(u32, 42), lista.items[0]);
    // Se houver leak, o teste FALHA automaticamente
}
```

## Padrão de Teste Anti-Leak

O `std.testing.allocator` é a ferramenta mais poderosa para detectar leaks:

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

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

    fn init(allocator: std.mem.Allocator) !MinhaStruct {
        return .{
            .dados = try allocator.alloc(u8, 100),
            .allocator = allocator,
        };
    }

    fn deinit(self: *MinhaStruct) void {
        self.allocator.free(self.dados);
    }
};

test "MinhaStruct não vaza memória" {
    var s = try MinhaStruct.init(std.testing.allocator);
    defer s.deinit();

    // Se deinit não liberar tudo, o teste falha com:
    // "Test failure: memory leak detected"
}
```

## Diagnóstico Avançado

### Habilitar Stack Traces para Alocações

```zig
var gpa = std.heap.GeneralPurposeAllocator(.{
    .stack_trace_frames = 10, // Captura 10 frames de stack
    .verbose_log = true,     // Log detalhado
}){};
```

Quando um leak é detectado, o GPA mostra exatamente onde a memória foi alocada:

```
error(gpa): leaked allocation of 1024 bytes
    src/main.zig:15:35 in main
    src/lib.zig:42:20 in criarBuffer
```

## Erros Relacionados

- [Memory leak](/erros/erro-memory-leak/) — Conceito geral de vazamento
- [OutOfMemory](/erros/erro-out-of-memory/) — Consequência de leaks acumulados
- [Double free](/erros/erro-double-free/) — Liberar memória duas vezes
- [Invalid free](/erros/erro-allocator-invalid-free/) — Liberar ponteiro inválido

## Links Úteis

- [Documentação oficial do Zig — GeneralPurposeAllocator](https://ziglang.org/documentation/master/#GeneralPurposeAllocator)
- [Receitas de testes de memória](/receitas/)
- [Tutorial sobre alocadores em Zig](/tutoriais/)
