std.heap — Alocadores de Memória
O módulo std.heap fornece implementações concretas da interface std.mem.Allocator. Cada alocador tem características diferentes, adequadas para cenários específicos de uso. A escolha correta do alocador impacta desempenho, uso de memória e facilidade de depuração.
Visão Geral
const std = @import("std");
const heap = std.heap;
O Zig oferece vários alocadores na biblioteca padrão, cada um com trade-offs diferentes:
| Alocador | Uso Principal | Overhead | Detecção de Bugs |
|---|---|---|---|
GeneralPurposeAllocator | Desenvolvimento e uso geral | Médio | Sim |
ArenaAllocator | Alocações temporárias em grupo | Baixo | Não |
page_allocator | Alocações grandes ou base para outros | Mínimo | Não |
FixedBufferAllocator | Sem syscalls, buffer pré-alocado | Zero | Não |
c_allocator | Interop com C | Mínimo | Não |
Alocadores Disponíveis
heap.GeneralPurposeAllocator
Alocador de uso geral com detecção de vazamentos de memória, double-free e uso após free. Ideal para desenvolvimento e depuração.
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
heap.ArenaAllocator
Alocador que permite liberar toda a memória de uma vez. Alocações individuais não são liberadas — apenas deinit() libera tudo.
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
const allocator = arena.allocator();
heap.page_allocator
Alocador que usa diretamente páginas de memória do sistema operacional via mmap/VirtualAlloc. Não tem estado — é uma constante global.
const allocator = std.heap.page_allocator;
heap.FixedBufferAllocator
Alocador sobre um buffer de tamanho fixo. Não faz nenhuma syscall.
var buf: [4096]u8 = undefined;
var fba = std.heap.FixedBufferAllocator.init(&buf);
const allocator = fba.allocator();
heap.c_allocator
Wrapper sobre malloc/free do C. Útil para interoperabilidade com bibliotecas C.
const allocator = std.heap.c_allocator;
Exemplo 1: Comparando Alocadores
const std = @import("std");
fn usarAlocador(allocator: std.mem.Allocator) !void {
var lista = std.ArrayList(u32).init(allocator);
defer lista.deinit();
for (0..100) |i| {
try lista.append(@intCast(i * 2));
}
std.debug.print("Lista com {d} itens, último: {d}\n", .{
lista.items.len,
lista.items[lista.items.len - 1],
});
}
pub fn main() !void {
// Com GeneralPurposeAllocator
{
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
std.debug.print("GPA: ", .{});
try usarAlocador(gpa.allocator());
}
// Com ArenaAllocator
{
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
std.debug.print("Arena: ", .{});
try usarAlocador(arena.allocator());
}
// Com FixedBufferAllocator
{
var buf: [8192]u8 = undefined;
var fba = std.heap.FixedBufferAllocator.init(&buf);
std.debug.print("FBA: ", .{});
try usarAlocador(fba.allocator());
}
// Com page_allocator
{
std.debug.print("Page: ", .{});
try usarAlocador(std.heap.page_allocator);
}
}
Exemplo 2: Escolha de Alocador por Contexto
const std = @import("std");
fn processarRequisicao(allocator: std.mem.Allocator) ![]u8 {
// Arena para dados temporários da requisição
var arena = std.heap.ArenaAllocator.init(allocator);
defer arena.deinit();
const temp = arena.allocator();
// Alocações temporárias — serão todas liberadas no defer
const header = try temp.alloc(u8, 256);
const body = try temp.alloc(u8, 1024);
_ = header;
_ = body;
// O resultado final usa o alocador do chamador
const resultado = try allocator.dupe(u8, "Resposta processada");
return resultado;
}
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
const resp = try processarRequisicao(allocator);
defer allocator.free(resp);
std.debug.print("{s}\n", .{resp});
}
Exemplo 3: Detecção de Vazamentos com GPA
const std = @import("std");
pub fn main() void {
var gpa = std.heap.GeneralPurposeAllocator(.{
.verbose_log = true, // Log detalhado (opcional)
}){};
defer {
const status = gpa.deinit();
switch (status) {
.ok => std.debug.print("Sem vazamentos!\n", .{}),
.leak => std.debug.print("VAZAMENTO detectado!\n", .{}),
}
}
const allocator = gpa.allocator();
// Alocação que será liberada corretamente
const dados1 = allocator.alloc(u8, 100) catch return;
allocator.free(dados1);
// Alocação que NÃO será liberada (vazamento intencional para demonstração)
_ = allocator.alloc(u8, 50) catch return;
// O defer do gpa.deinit() reportará o vazamento
}
Padrões Comuns
Hierarquia de Alocadores
// Base: page_allocator (syscalls)
// -> GPA (detecção de bugs em desenvolvimento)
// -> Arena (alocações temporárias por escopo)
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
var arena = std.heap.ArenaAllocator.init(gpa.allocator());
Alocador para Testes
test "minha função" {
// testing.allocator detecta vazamentos automaticamente
const resultado = try minhaFuncao(std.testing.allocator);
defer std.testing.allocator.free(resultado);
try std.testing.expect(resultado.len > 0);
}
Módulos Relacionados
- std.mem.Allocator — Interface Allocator
- GeneralPurposeAllocator — Detalhes do GPA
- ArenaAllocator — Detalhes da Arena
- page_allocator — Detalhes do page_allocator
- FixedBufferAllocator — Detalhes do FBA