Fixed Buffer Allocator em Zig — O que é e Como Usar
Definição
O Fixed Buffer Allocator (std.heap.FixedBufferAllocator) em Zig é um alocador que distribui memória a partir de um buffer pré-alocado de tamanho fixo. Não faz nenhuma chamada ao sistema operacional — toda memória vem do buffer fornecido na inicialização. Quando o buffer acaba, qualquer nova alocação retorna error.OutOfMemory.
É o alocador ideal para sistemas embarcados, contextos sem SO e situações onde alocação dinâmica do SO não é desejável.
Por que Fixed Buffer Allocator Importa
- Zero syscalls: Não depende do sistema operacional para memória.
- Determinístico: Tempo de alocação previsível — importante para real-time.
- Embarcados: Funciona em plataformas freestanding sem heap.
- Stack-based: O buffer pode viver na stack, eliminando uso de heap completamente.
Exemplo Prático
Uso Básico
const std = @import("std");
pub fn main() !void {
// Buffer na stack — sem heap!
var buffer: [4096]u8 = undefined;
var fba = std.heap.FixedBufferAllocator.init(&buffer);
const allocator = fba.allocator();
// Alocações vêm do buffer de 4096 bytes
const dados = try allocator.alloc(u8, 100);
const numeros = try allocator.alloc(u32, 50);
dados[0] = 'Z';
numeros[0] = 42;
std.debug.print("Dados: {c}, Números: {}\n", .{ dados[0], numeros[0] });
// Quando o buffer acabar:
// const grande = try allocator.alloc(u8, 10000); // error.OutOfMemory
}
Para Funções que Precisam de Allocator
const std = @import("std");
fn formatar(allocator: std.mem.Allocator, nome: []const u8, idade: u32) ![]u8 {
return std.fmt.allocPrint(allocator, "{s} tem {} anos", .{ nome, idade });
}
pub fn main() !void {
var buffer: [256]u8 = undefined;
var fba = std.heap.FixedBufferAllocator.init(&buffer);
const texto = try formatar(fba.allocator(), "Maria", 25);
std.debug.print("{s}\n", .{texto});
}
Em Sistemas Embarcados
const std = @import("std");
// Buffer global para embarcados (sem heap disponível)
var memoria_global: [8192]u8 = undefined;
var alocador_global = std.heap.FixedBufferAllocator.init(&memoria_global);
pub fn setup() !void {
const alloc = alocador_global.allocator();
var sensores = try alloc.alloc(u16, 10);
_ = sensores;
// Processamento com memória limitada e previsível
}
Reset para Reutilização
fn processarMensagens(mensagens: []const Mensagem) !void {
var buffer: [1024]u8 = undefined;
var fba = std.heap.FixedBufferAllocator.init(&buffer);
for (mensagens) |msg| {
// Reset "zera" o alocador — permite reutilizar todo o buffer
fba.reset();
const alloc = fba.allocator();
const processada = try processar(alloc, msg);
try enviar(processada);
}
}
Combinando com Arena
var buffer: [65536]u8 = undefined;
var fba = std.heap.FixedBufferAllocator.init(&buffer);
// Arena sobre FBA — melhor gerenciamento de alocações múltiplas
var arena = std.heap.ArenaAllocator.init(fba.allocator());
defer arena.deinit();
Armadilhas Comuns
- OutOfMemory inesperado: O buffer tem tamanho fixo. Se as alocações excederem o tamanho,
OutOfMemoryé retornado. Dimensione o buffer adequadamente. - Fragmentação:
freeindividual pode criar lacunas que não podem ser reaproveitadas facilmente. Usereset()quando possível. - Buffer na stack: Buffers muito grandes na stack causam stack overflow. Para buffers grandes, use variáveis globais ou
comptime. - Esquecer o
reset: Em loops, esquecer de resetar o FBA faz o buffer esgotar rapidamente. - Alinhamento: O FBA respeita requisitos de alinhamento, o que pode desperdiçar bytes entre alocações.
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
- Stack vs Heap — Diferença entre pilha e heap