General Purpose Allocator em Zig — O que é e Como Usar
Definição
O General Purpose Allocator (GPA, std.heap.GeneralPurposeAllocator) é o alocador de uso geral da biblioteca padrão do Zig. Ele combina performance razoável com detecção integrada de bugs de memória: vazamentos (memory leaks), double-free, use-after-free e overflows de buffer. É o alocador recomendado para a maioria das aplicações e especialmente para desenvolvimento e testes.
Por que o GPA Importa
- Detecção de bugs: Em modo Debug, detecta automaticamente os erros de memória mais comuns.
- Uso geral: Funciona bem para a maioria dos padrões de alocação.
- Configurável: Diversas opções para ajustar comportamento e segurança.
- Production-ready: Pode ser usado em produção com configurações de release.
Exemplo Prático
Uso Básico com Detecção de Leaks
const std = @import("std");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer {
const status = gpa.deinit();
if (status == .leak) {
std.debug.print("ALERTA: Vazamento de memória detectado!\n", .{});
}
}
const allocator = gpa.allocator();
// Alocação normal
const dados = try allocator.alloc(u8, 100);
defer allocator.free(dados);
// Se esquecêssemos o defer acima, gpa.deinit() detectaria o leak
std.debug.print("Alocado {} bytes\n", .{dados.len});
}
Configuração Personalizada
const std = @import("std");
var gpa = std.heap.GeneralPurposeAllocator(.{
// Registra stack traces de alocação para debug
.stack_trace_frames = 8,
// Não libera memória de volta ao SO (mais rápido para debug)
.retain_metadata = true,
// Desabilita safety checks para release
.safety = true,
}){};
Usando em Testes
const std = @import("std");
const testing = std.testing;
fn criarLista(allocator: std.mem.Allocator) !std.ArrayList(u32) {
var lista = std.ArrayList(u32).init(allocator);
try lista.append(1);
try lista.append(2);
try lista.append(3);
return lista;
}
test "sem memory leak" {
// testing.allocator já é um GPA com detecção de leaks!
var lista = try criarLista(testing.allocator);
defer lista.deinit();
try testing.expectEqual(@as(usize, 3), lista.items.len);
// Se esquecer o defer, o teste FALHA automaticamente
}
Detectando Double Free
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
const dados = try allocator.alloc(u8, 100);
allocator.free(dados);
// allocator.free(dados); // PANIC: double free detectado!
}
GPA como Alocador Principal da Aplicação
const std = @import("std");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
var app = try App.init(allocator);
defer app.deinit();
try app.run();
}
O que o GPA Detecta
| Bug | Detecção | Modo |
|---|---|---|
| Memory leak | No deinit() | Debug + ReleaseSafe |
| Double free | No free() | Debug + ReleaseSafe |
| Use-after-free | No acesso | Debug |
| Buffer overflow | Na escrita | Debug |
Armadilhas Comuns
- Esquecer de chamar
deinit(): Semdeinit(), a detecção de leaks não ocorre. Sempre usedefer _ = gpa.deinit(). - Performance em hot paths: O GPA é mais lento que alocadores especializados. Para hot paths, considere
ArenaAllocator. - Ignorar o status de deinit: O retorno de
deinit()informa se houve leak. Verifique-o. - Usar em freestanding: O GPA depende do sistema operacional. Em embarcados, use
FixedBufferAllocator. - Confundir com
testing.allocator:testing.allocatorjá é um GPA configurado para testes. Não crie outro dentro de testes.
Termos Relacionados
- Allocator — Interface de alocação de memória
- Arena Allocator — Alocador para liberação em lote
- Page Allocator — Alocador baseado em páginas
- Fixed Buffer Allocator — Alocador com buffer fixo
- Memory Leak — Vazamentos de memória