page_allocator — Alocador de Páginas
O std.heap.page_allocator é um alocador que solicita memória diretamente ao sistema operacional em unidades de páginas. Ele usa mmap no Linux/macOS e VirtualAlloc no Windows. É o alocador mais simples disponível e serve frequentemente como base para alocadores mais sofisticados.
Visão Geral
const std = @import("std");
const page_allocator = std.heap.page_allocator;
O page_allocator é uma constante global — não tem estado mutável e não precisa ser inicializado ou desinicializado. Cada alocação resulta em uma ou mais syscalls ao SO.
Características:
- Alocações são sempre alinhadas ao tamanho de página (geralmente 4096 bytes)
- Overhead mínimo de metadados
- Cada
alloc/freeé uma syscall - Não há fragmentação interna entre alocações
- Ideal como base para
ArenaAllocator
Uso
// Acesso direto — sem inicialização necessária
const allocator = std.heap.page_allocator;
// Alocação
const dados = try allocator.alloc(u8, 1024);
defer allocator.free(dados);
Exemplo 1: Uso Direto para Alocações Grandes
const std = @import("std");
pub fn main() !void {
const allocator = std.heap.page_allocator;
// Alocar 1 MB de memória
const tamanho = 1024 * 1024;
const buffer = try allocator.alloc(u8, tamanho);
defer allocator.free(buffer);
// Preencher com dados
@memset(buffer, 0xAA);
std.debug.print("Alocados {d} bytes com page_allocator\n", .{buffer.len});
std.debug.print("Primeiros bytes: {x:0>2} {x:0>2} {x:0>2} {x:0>2}\n", .{
buffer[0], buffer[1], buffer[2], buffer[3],
});
}
Exemplo 2: Como Base para ArenaAllocator
O uso mais comum do page_allocator é como alocador subjacente para outros alocadores:
const std = @import("std");
pub fn main() !void {
// Arena sobre page_allocator — combinação muito comum
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
const allocator = arena.allocator();
// Muitas alocações pequenas são eficientes via arena
var lista = std.ArrayList(u32).init(allocator);
for (0..1000) |i| {
try lista.append(@intCast(i));
}
std.debug.print("Lista com {d} itens\n", .{lista.items.len});
// Tudo liberado de uma vez pelo arena.deinit()
}
Exemplo 3: Comparação de Granularidade
const std = @import("std");
pub fn main() !void {
const page = std.heap.page_allocator;
// Mesmo pedindo poucos bytes, page_allocator aloca pelo menos uma página
const pequeno = try page.alloc(u8, 1);
defer page.free(pequeno);
const medio = try page.alloc(u8, 4096);
defer page.free(medio);
const grande = try page.alloc(u8, 10000);
defer page.free(grande);
std.debug.print("Pedido: 1 byte, recebido: {d} bytes\n", .{pequeno.len});
std.debug.print("Pedido: 4096 bytes, recebido: {d} bytes\n", .{medio.len});
std.debug.print("Pedido: 10000 bytes, recebido: {d} bytes\n", .{grande.len});
// O page_allocator retorna exatamente o que foi pedido,
// mas internamente aloca páginas inteiras.
// O espaço extra dentro da última página não é acessível.
}
Padrões Comuns
Base para Arena em Servidor
// Padrão para servidor: arena sobre page_allocator
fn handler() !void {
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
try processarRequisicao(arena.allocator());
}
Alocação de Buffers Grandes
// Para buffers grandes, page_allocator é eficiente
const buffer_io = try std.heap.page_allocator.alloc(u8, 64 * 1024);
defer std.heap.page_allocator.free(buffer_io);
Quando Usar page_allocator Diretamente
Use diretamente quando:
- Alocações são grandes e poucas
- Você precisa de um alocador sem estado
- É a base para outro alocador
- Simplicidade é mais importante que eficiência para alocações pequenas
Evite usar diretamente quando:
- Faz muitas alocações pequenas (overhead de syscalls)
- Precisa de detecção de vazamentos (use GPA)
- Precisa de alocações muito frequentes (use arena)
Considerações de Desempenho
Cada chamada a alloc e free resulta em uma syscall:
- Linux:
mmap/munmap - Windows:
VirtualAlloc/VirtualFree
Syscalls têm custo na ordem de microsegundos. Para milhares de alocações pequenas, use ArenaAllocator ou GeneralPurposeAllocator como camada intermediária.
Módulos Relacionados
- std.mem.Allocator — Interface Allocator
- std.heap — Visão geral dos alocadores
- ArenaAllocator — Alocador de arena (usa page_allocator como base)
- GeneralPurposeAllocator — Alocador de uso geral
- FixedBufferAllocator — Alternativa sem syscalls