GeneralPurposeAllocator — Alocador de Uso Geral
O GeneralPurposeAllocator (GPA) é o alocador recomendado para uso geral em Zig. Ele combina bom desempenho com recursos de depuração poderosos, incluindo detecção de vazamentos de memória, double-free, uso após free e corrupção de heap.
Visão Geral
const std = @import("std");
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
O GPA é o alocador ideal para:
- Desenvolvimento e depuração
- Aplicações de uso geral
- Quando detecção de bugs de memória é desejada
Configuração
pub fn GeneralPurposeAllocator(comptime config: Config) type
pub const Config = struct {
/// Ativar log detalhado de alocações
verbose_log: bool = false,
/// Número de stack frames a capturar para cada alocação
stack_trace_frames: usize = 8,
/// Manter metadados para detecção de use-after-free
safety: bool = std.debug.runtime_safety,
/// Não retornar memória ao SO (melhor detecção de bugs)
never_unmap: bool = false,
/// Colocar páginas de guarda entre alocações
page_guard: bool = false,
};
Métodos
// Obtém a interface Allocator
pub fn allocator(self: *Self) std.mem.Allocator
// Libera recursos e reporta vazamentos
// Retorna .ok ou .leak
pub fn deinit(self: *Self) enum { ok, leak }
Exemplo 1: Uso Básico com Detecção de Vazamentos
const std = @import("std");
pub fn main() void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer {
const resultado = gpa.deinit();
if (resultado == .leak) {
std.debug.print("AVISO: Vazamento de memória detectado!\n", .{});
} else {
std.debug.print("Memória OK: sem vazamentos.\n", .{});
}
}
const allocator = gpa.allocator();
// Alocação que é liberada corretamente
const dados = allocator.alloc(u8, 256) catch {
std.debug.print("Falha na alocação\n", .{});
return;
};
defer allocator.free(dados);
// Usar os dados
@memset(dados, 'A');
std.debug.print("Alocados {d} bytes: {s}...\n", .{ dados.len, dados[0..10] });
}
Exemplo 2: Configuração Avançada para Depuração
const std = @import("std");
pub fn main() void {
// Configuração mais agressiva para encontrar bugs
var gpa = std.heap.GeneralPurposeAllocator(.{
.stack_trace_frames = 16, // Mais frames no stack trace
.never_unmap = true, // Detecta use-after-free mais cedo
}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
// Simular uso típico de aplicação
var lista = std.ArrayList([]const u8).init(allocator);
defer {
for (lista.items) |item| allocator.free(item);
lista.deinit();
}
const nomes = [_][]const u8{ "Zig", "Rust", "Go", "C" };
for (nomes) |nome| {
const copia = allocator.dupe(u8, nome) catch continue;
lista.append(copia) catch {
allocator.free(copia);
continue;
};
}
std.debug.print("Linguagens:\n", .{});
for (lista.items) |item| {
std.debug.print(" - {s}\n", .{item});
}
}
Exemplo 3: GPA como Alocador Base para Arena
const std = @import("std");
fn processarLote(allocator: std.mem.Allocator, items: []const u32) !u64 {
// Arena para alocações temporárias deste lote
var arena = std.heap.ArenaAllocator.init(allocator);
defer arena.deinit();
const temp = arena.allocator();
// Alocações temporárias (liberadas automaticamente pelo arena)
var resultados = try temp.alloc(u64, items.len);
var soma: u64 = 0;
for (items, 0..) |item, i| {
resultados[i] = @as(u64, item) * @as(u64, item);
soma += resultados[i];
}
return soma;
}
pub fn main() !void {
// GPA como alocador base — detecta vazamentos do arena incorretamente usado
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer {
const status = gpa.deinit();
std.debug.print("Status da memória: {}\n", .{status});
}
const allocator = gpa.allocator();
const items = [_]u32{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
const resultado = try processarLote(allocator, &items);
std.debug.print("Soma dos quadrados: {d}\n", .{resultado});
}
Padrões Comuns
Padrão de Inicialização Típico
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
try executar(allocator);
}
Verificação em Modo Release
Em builds de release, as verificações de segurança são desativadas por padrão para melhor desempenho:
// Em debug: detecção completa de bugs
// Em release: sem overhead de segurança
var gpa = std.heap.GeneralPurposeAllocator(.{
.safety = true, // Forçar segurança mesmo em release
}){};
Alternativa para Produção
Para aplicações em produção onde o desempenho é crítico, considere usar std.heap.c_allocator ou page_allocator com arena:
const allocator = if (builtin.mode == .Debug)
gpa.allocator()
else
std.heap.c_allocator;
Considerações de Desempenho
O GPA tem overhead moderado em comparação com malloc:
- Mantém metadados por alocação para detecção de bugs
- Captura stack traces (configurável)
- Verifica integridade em
free()
Para código onde desempenho de alocação é crítico, considere ArenaAllocator ou page_allocator.
Módulos Relacionados
- std.mem.Allocator — Interface Allocator
- std.heap — Visão geral dos alocadores
- ArenaAllocator — Alocador de arena
- page_allocator — Alocador de páginas
- FixedBufferAllocator — Alocador sem syscalls