Memory Leak em Zig — O que é e Como Evitar
Definição
Um memory leak (vazamento de memória) ocorre quando um programa aloca memória no heap mas nunca a libera. Com o tempo, a memória disponível diminui, podendo levar a lentidão, OutOfMemory e, eventualmente, falha total do programa.
Em Zig, onde o gerenciamento de memória é manual, memory leaks são um risco real. Porém, a linguagem oferece ferramentas excelentes para detectá-los e preveni-los: o padrão defer e o GeneralPurposeAllocator com detecção integrada.
Por que Memory Leaks Importam
- Degradação progressiva: O programa fica cada vez mais lento até falhar.
- Servidores de longa duração: Leaks pequenos se acumulam ao longo de horas/dias.
- Recursos limitados: Em embarcados, qualquer leak é crítico.
- Difícil diagnóstico: Leaks muitas vezes só se manifestam em produção.
Exemplo Prático
Memory Leak Simples
const std = @import("std");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer {
const status = gpa.deinit();
if (status == .leak) @panic("LEAK DETECTADO!");
}
const allocator = gpa.allocator();
// LEAK! Alocamos mas nunca liberamos
const dados = try allocator.alloc(u8, 1024);
_ = dados;
// Ao sair, gpa.deinit() detecta o leak
}
Corrigido com Defer
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
const dados = try allocator.alloc(u8, 1024);
defer allocator.free(dados); // Agora está correto!
// Usar dados...
}
Leak em Estruturas Aninhadas
const std = @import("std");
const Usuario = struct {
nome: []u8,
email: []u8,
allocator: std.mem.Allocator,
pub fn deinit(self: *Usuario) void {
self.allocator.free(self.nome);
self.allocator.free(self.email);
}
};
fn criarUsuario(allocator: std.mem.Allocator) !Usuario {
const nome = try allocator.dupe(u8, "Maria Silva");
errdefer allocator.free(nome); // Libera nome se email falhar
const email = try allocator.dupe(u8, "maria@email.com");
// Sem errdefer para email — se chegarmos aqui, tudo OK
return Usuario{
.nome = nome,
.email = email,
.allocator = allocator,
};
}
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
var usuario = try criarUsuario(gpa.allocator());
defer usuario.deinit(); // Libera TODOS os campos internos
}
Detecção em Testes
const std = @import("std");
const testing = std.testing;
test "função não vaza memória" {
// testing.allocator detecta leaks automaticamente
var lista = std.ArrayList(u8).init(testing.allocator);
defer lista.deinit(); // Sem isto, o teste FALHA
try lista.appendSlice("Zig Brasil");
try testing.expectEqual(@as(usize, 10), lista.items.len);
}
Padrões de Prevenção
| Padrão | Descrição |
|---|---|
defer free | Liberar imediatamente após alocar |
errdefer free | Liberar em caso de erro parcial |
deinit() em structs | Métodos que liberam todos os campos |
| Arena Allocator | Liberar tudo de uma vez |
| GPA em testes | Detecção automática em cada teste |
Causas Comuns de Leaks
// 1. Sobrescrever ponteiro sem liberar
var ptr = try allocator.alloc(u8, 100);
ptr = try allocator.alloc(u8, 200); // LEAK: primeiro alloc perdido!
// 2. Return antecipado sem cleanup
const dados = try allocator.alloc(u8, 100);
if (condicao) return error.Falha; // LEAK: dados não liberados
allocator.free(dados);
// 3. Exceção em lista de inicialização
// (Usar errdefer para proteger)
Armadilhas Comuns
- Confiar apenas em
defer: Se a alocação e a liberação estão em funções diferentes,defernão resolve. Implementedeinit(). - ArrayList/HashMap sem
deinit: Coleções da std guardam memória internamente. Sempre chamedeinit(). - Leak em loops: Alocar dentro de um loop sem liberar a cada iteração acumula leaks.
- Ignorar erros de alocação parcial: Sem
errdefer, falhas no meio de inicialização vazam recursos já alocados.
Termos Relacionados
- Allocator — Interface de alocação de memória
- Defer — Limpeza garantida ao sair do escopo
- Errdefer — Limpeza condicional em caso de erro
- General Purpose Allocator — GPA com detecção de leaks
- Dangling Pointer — Ponteiros para memória liberada