Page Allocator em Zig — O que é e Como Usar
Definição
O Page Allocator (std.heap.page_allocator) em Zig é o alocador mais simples disponível na biblioteca padrão. Ele solicita memória diretamente ao sistema operacional em unidades de páginas (tipicamente 4KB em x86_64). Cada chamada a alloc resulta em uma chamada de sistema (mmap no Linux, VirtualAlloc no Windows).
É o “alocador de último recurso” — confiável e simples, mas não eficiente para alocações pequenas ou frequentes.
Por que Page Allocator Importa
- Simplicidade: Sem estado interno, sem configuração. Está sempre disponível.
- Sem fragmentação: Cada alocação é independente no espaço de endereçamento.
- Base para outros alocadores: O
ArenaAllocatore oGeneralPurposeAllocatorpodem usar o page allocator como backend. - Ideal para alocações grandes: Quando você precisa de buffers de megabytes, é a escolha natural.
Exemplo Prático
Uso Básico
const std = @import("std");
pub fn main() !void {
const allocator = std.heap.page_allocator;
// Aloca pelo menos 1 página (4096 bytes no x86_64)
const buffer = try allocator.alloc(u8, 1000);
defer allocator.free(buffer);
@memset(buffer, 'Z');
std.debug.print("Alocado {} bytes\n", .{buffer.len});
}
Como Backend para Arena
const std = @import("std");
pub fn main() !void {
// Arena usa page_allocator como fonte de memória
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
const allocator = arena.allocator();
// Muitas alocações pequenas — eficientes com arena
var i: usize = 0;
while (i < 1000) : (i += 1) {
_ = try allocator.alloc(u8, 64);
}
// Tudo liberado de uma vez com arena.deinit()
}
Alocação de Buffer Grande
fn carregarArquivoGrande(caminho: []const u8) ![]u8 {
const allocator = std.heap.page_allocator;
const arquivo = try std.fs.cwd().openFile(caminho, .{});
defer arquivo.close();
const stat = try arquivo.stat();
const buffer = try allocator.alloc(u8, stat.size);
errdefer allocator.free(buffer);
const lidos = try arquivo.readAll(buffer);
return buffer[0..lidos];
}
Comparação de Tamanho de Alocação
const std = @import("std");
pub fn main() !void {
const allocator = std.heap.page_allocator;
// Mesmo pedindo 1 byte, o SO aloca uma página inteira (4096)
const um_byte = try allocator.alloc(u8, 1);
defer allocator.free(um_byte);
// Pedindo exatamente uma página
const uma_pagina = try allocator.alloc(u8, 4096);
defer allocator.free(uma_pagina);
std.debug.print("Pedido: 1 byte, recebido: {} bytes\n", .{um_byte.len});
std.debug.print("Pedido: 4096 bytes, recebido: {} bytes\n", .{uma_pagina.len});
}
Quando Usar Page Allocator
| Situação | Recomendado? |
|---|---|
| Alocações grandes (> 4KB) | Sim |
| Muitas alocações pequenas | Não (use Arena ou GPA) |
| Backend para outros alocadores | Sim |
| Prototipação rápida | Sim |
| Sistemas embarcados | Não (sem SO) |
Armadilhas Comuns
- Desperdício para alocações pequenas: Pedir 1 byte aloca uma página inteira (4096 bytes). Para dados pequenos, use
GeneralPurposeAllocatorouArenaAllocator. - Performance em alocações frequentes: Cada
alloc/freeé uma syscall. Para muitas alocações, use um alocador que faz buffering. - Não disponível em freestanding: Em plataformas sem SO (embarcados), não há page allocator. Use
FixedBufferAllocator. - Alinhamento fixo: O page allocator sempre alinha a páginas. Isso é mais que suficiente para qualquer tipo de dado.
Termos Relacionados
- Allocator — Interface de alocação de memória
- Arena Allocator — Alocador de arena
- General Purpose Allocator — Alocador de uso geral
- Fixed Buffer Allocator — Alocador com buffer fixo
- Stack vs Heap — Diferença entre pilha e heap