Seu programa pode ficar mais rápido e seguro sem mudar o código: conheça o alocador mimalloc

Escrito por
Emanuel Negromonte
Emanuel Negromonte é Jornalista, Mestre em Tecnologia da Informação e atualmente cursa a segunda graduação em Engenharia de Software. Com 14 anos de experiência escrevendo sobre...

Acelere e proteja seus apps com um drop-in do malloc.

Imagine poder acelerar seu programa, reduzir seu consumo de memória e ainda torná-lo mais seguro contra vulnerabilidades de heap, tudo isso com um único comando. Essa é a promessa do mimalloc, um alocador de memória (memory allocator) de propósito geral que se destaca pela performance e design inteligente.

O que é o mimalloc e por que ele é diferente?

O mimalloc allocator (pronuncia-se “mi-malloc”) nasceu do trabalho de Daan Leijen para os runtimes das linguagens Koka e Lean — ambientes onde latência previsível e baixo overhead são cruciais. Hoje, ele foi além do laboratório: é usado em serviços distribuídos de larga escala em milhares de máquinas, sustentando cargas reais com picos, múltiplas threads e requisitos de latência de pior caso. Em outras palavras, não é “apenas mais um malloc”: é uma peça de infraestrutura nível industrial.

Por que desenvolvedores e empresas estão olhando para ele como drop-in replacement do malloc padrão?

  • Pequeno e consistente: cerca de ~10k linhas de código, com estruturas de dados simples e previsíveis. Isso favorece auditorias, portabilidade e integração direta em projetos (inclusive como “single source file”).
  • Rápido: em uma ampla bateria de benchmarks, o mimalloc frequentemente supera alocadores consagrados como jemalloc e tcmalloc — e, melhor ainda, faz isso de maneira consistente, em cenários variados.
  • Seguro: modo “secure” com guard pages, listas livres criptografadas, randomização e detecção de double-free. Quer reforçar ainda mais? Há também um modo “guarded” que coloca páginas de proteção atrás de objetos amostrados para flagrar estouros de buffer no ato.
  • Bounded: sem “blowup”, com tempos de alocação de pior caso limitados (até os limites do SO), overhead de metadados muito baixo (~0,2%) e ausência de pontos internos de contenção (usa primitivos atômicos).
  • Cross-platform de verdade: Windows, macOS, Linux, BSDs, WASM, Haiku, musl — e com excelente suporte a “override” dinâmico do alocador padrão.
  • Heaps de primeira classe: você pode criar múltiplos heaps independentes (por componente, subsistema ou fase do app) e descartá-los de uma vez, sem desalocar objeto por objeto.

Em termos de versões, o projeto evolui ativamente: há releases estáveis das linhas v1 e v2 e um v3 em beta com avanços na partilha de memória entre threads. As mais recentes (no momento da escrita): v3.1.5 (beta) de 13/06/2025, v2.2.4 de 09/06/2025 e v1.9.4 de 09/06/2024 — sem se afundar em changelogs, o recado é claro: o ritmo é vivo e as correções chegam rápido.

As grandes ideias: multi-sharding e liberação de memória otimizada

LpnDtOdL image
Seu programa pode ficar mais rápido e seguro sem mudar o código: conheça o alocador mimalloc 6

A mágica do mimalloc não vem de uma única técnica, mas de um conjunto de escolhas pragmáticas e bem amarradas. Duas delas se destacam para quem vive o dia a dia de sistemas concorrentes.

1) Free list sharding (e o “multi-sharding”)
Em muitos alocadores, objetos livres de uma mesma classe de tamanho acabam numa única “lista livre” global. Isso facilita, mas cria gargalos quando muitas threads disputam o mesmo ponto de acesso. O mimalloc parte de um princípio simples: fragmentar para conquistar. Em vez de uma grande fila, ele mantém muitas filas menores por “página” interna de alocação (típ. 64 KiB em 64-bit) — e dá um passo além com o free list multi-sharding.

A analogia é direta: pense em um supermercado. Uma fila única para todos os caixas parece “justa”, mas vira um gargalo gigante nos horários de pico. O mimalloc prefere milhares de filas locais: cada página tem suas próprias listas, e, dentro de cada página, há listas separadas para liberações locais (da própria thread) e concurrent frees (liberações feitas por outras threads). Na prática, liberar a partir de outra thread vira um único CAS, distribuindo naturalmente a contenção. Resultado? Menos briga por locks, melhor localidade (coisas alocadas juntas ficam próximas na memória) e escala em máquinas com muitos núcleos.

ga3JtrgY image 1
Seu programa pode ficar mais rápido e seguro sem mudar o código: conheça o alocador mimalloc 7

2) Eager page purging (liberação agressiva para o SO)
Outro ganho vem do comportamento quando páginas internas ficam vazias. No mimalloc, isso ocorre com mais frequência por causa do sharding — e quando acontece, a página é marcada como “não usada” pelo sistema operacional (reset/decommit). Em programas de longa execução, isso reduz pressão de memória real e fragmentação, sem você precisar fazer micromanagement do heap. E se o seu perfil de carga exigir ajustes, há controles finos (por exemplo, MIMALLOC_PURGE_DELAY) para equilibrar throughput e pegada de memória.

5cmzV53t image 2
Seu programa pode ficar mais rápido e seguro sem mudar o código: conheça o alocador mimalloc 8

Essas decisões vêm acompanhadas de outros toques de engenharia: boa compatibilidade com páginas enormes (útil para serviços parrudos), opções para ambientes NUMA, estatísticas detalhadas no modo debug e aleatorização interna para mitigar padrões previsíveis de ataque e de fragmentação.

6JrUpBCV image 3
Seu programa pode ficar mais rápido e seguro sem mudar o código: conheça o alocador mimalloc 9

Como começar a usar o mimalloc

A beleza do mimalloc allocator é que você pode experimentar sem tocar no código. Em sistemas ELF (Linux, BSD, etc.), basta pré-carregar a biblioteca e executar seu binário normalmente:

LD_PRELOAD=/usr/lib/libmimalloc.so  myprogram

Sim, é só isso — literalmente um comando. Quer confirmar que está em uso? Rode com MIMALLOC_VERBOSE=1 ou, em builds de debug, MIMALLOC_SHOW_STATS=1 para imprimir estatísticas ao final da execução. Em macOS, o conceito é semelhante via DYLD_INSERT_LIBRARIES, respeitando as restrições de segurança da plataforma. Em Windows, há um mecanismo de redirecionamento por DLL que intercepta as chamadas do runtime C — com algumas condições (como usar o CRT dinâmico e linkar com a export library da DLL do mimalloc). O ponto crucial: o projeto fornece o caminho para override dinâmico nas três grandes plataformas.

Se preferir adotar de forma “nativa”, linke a sua aplicação com a lib do mimalloc e use a API mi_ diretamente (mi_malloc, mi_free, mi_realloc…). Em C++, inclua o cabeçalho mimalloc-new-delete.h em um único TU para sobrescrever globalmente new/delete — um caminho simples para capturar praticamente todas as alocações da aplicação (e, de quebra, evitar misturar heaps diferentes). Usa CMake? O pacote suporta find_package(mimalloc) para vincular de forma limpa, seja dinâmica (mimalloc) ou estática (mimalloc-static).

Quer testar em produção com mais resiliência?

  • Modo secure (-DMI_SECURE=ON): adiciona guard pages, criptografia de ponteiros nas free lists e randomização; o custo típico é modesto (na casa de ~10% nos testes do projeto), e o ganho em segurança é real.
  • Modo guarded (-DMI_GUARDED=ON): amostragem controlada de objetos com guard pages para pegar estouros de buffer em tempo real (configure com MIMALLOC_GUARDED_SAMPLE_RATE).
  • Modo debug (-DCMAKE_BUILD_TYPE=Debug): estatísticas de granularidade fina, detecção de double-free, overflows byte-a-byte e mais.

Trabalha com cargas enormes? Experimente as opções avançadas:

  • MIMALLOC_ALLOW_LARGE_OS_PAGES / MIMALLOC_RESERVE_HUGE_OS_PAGES: para páginas grandes/imensas quando apropriado (atenção a ambientes com memória fragmentada).
  • MIMALLOC_PURGE_DELAY: controle de quando páginas internas “vazias” são devolvidas ao SO (0 = imediato; valores maiores podem melhorar performance às custas de picos de RSS).
  • Afinidade NUMA e arenas/segmentos ajustáveis na linha v3, que melhoram o compartilhamento entre threads em workloads certos.

E se você quiser uma migração gradual? O mimalloc convive bem com outros alocadores no mesmo processo — uma propriedade útil para incorporar componentes aos poucos. Para projetos onde é essencial observar todas as alocações “como estão”, o time também documenta caminhos de integração com ferramentas como Valgrind/ASAN (úteis em testes e CI).

Quem mais se beneficia?

  • Serviços de baixa latência e alta concorrência: filas de rede, brokers, motores de busca internos, analytics em tempo real… o multi-sharding ajuda a manter a fila de alocações/limpezas fluindo sem brigas.
  • Aplicações desktop e dev tools: IDEs, compiladores e sistemas de build (como o próprio Lean) se beneficiam de localidade melhor — coisas alocadas juntas ficam próximas, o que reduz cache misses e tempo total.
  • Games e simulações: heaps dedicados por subsistema permitem descarte em lote no fim de uma fase; previsibilidade de alocação ajuda a estabilizar frametimes.
  • Cargas com picos e rajadas: a política agressiva de purga de páginas reduz “ressaca” de memória depois que o pico passa.

No fim do dia, a pergunta que importa é: vale a pena o teste A/B? Dado o custo de adoção irrisório — literalmente um LD_PRELOAD — e os relatos/benchmarks onde mimalloc supera jemalloc e tcmalloc em performance (com footprint competitivo) e adiciona segurança significativa, a resposta prática costuma ser: sim, e quanto antes.

Compartilhe este artigo