O módulo tracemalloc rastreia alocações de memória realizadas pelo Python e registra onde elas ocorreram. Ele permite medir memória atual e pico, criar snapshots, agrupar alocações por arquivo ou linha, comparar estados e aplicar filtros. É uma ferramenta importante para investigar crescimento de memória, caches sem limite, estruturas mantidas por engano e regressões entre versões de código.
tracemalloc não mede toda a memória residente do processo. Bibliotecas nativas, buffers externos, memória do sistema operacional, GPU e alocações que não passam pelos hooks rastreados podem ficar fora do resultado. Use-o em conjunto com métricas de RSS, ferramentas do sistema e conhecimento do workload.
Inicie o rastreamento
Chame start() antes do trecho que deseja observar.
import tracemalloc
tracemalloc.start()
executar_aplicacao()
Começar cedo captura imports e inicialização; começar tarde reduz ruído e overhead.
Número de frames
start(nframe) define quantos frames de traceback guardar por alocação.
tracemalloc.start(10)
Mais frames ajudam a entender a origem completa, mas aumentam consumo e custo.
Verifique se está ativo
is_tracing() informa se o rastreamento está habilitado.
if not tracemalloc.is_tracing():
tracemalloc.start(5)
Uma biblioteca não deve iniciar ou parar tracing global sem documentar o impacto sobre a aplicação.
Memória atual e pico
get_traced_memory() retorna bytes atuais e pico rastreados.
atual, pico = tracemalloc.get_traced_memory()
print(atual, pico)
O pico é útil para detectar uma operação temporariamente cara mesmo quando a memória é liberada depois.
Resete o pico
reset_peak() redefine o valor máximo sem apagar alocações atuais.
tracemalloc.reset_peak()
executar_etapa()
atual, pico_etapa = tracemalloc.get_traced_memory()
Isso permite medir picos por fase.
Crie um snapshot
take_snapshot() captura as alocações rastreadas naquele instante.
snapshot = tracemalloc.take_snapshot()
Snapshots podem consumir memória. Não crie continuamente em produção sem controle.
Estatísticas por linha
statistics("lineno") agrupa alocações por linha.
for estatistica in snapshot.statistics("lineno")[:10]:
print(estatistica)
Observe tamanho total, contagem e média. Uma linha com muitas pequenas alocações pode ser tão importante quanto uma alocação grande.
Por arquivo ou traceback
Use filename para agrupar por arquivo e traceback para distinguir caminhos de chamada.
top = snapshot.statistics("traceback")[:5]
for item in top:
print(item.size, item.count)
for frame in item.traceback.format():
print(frame)
Tracebacks são mais detalhados e podem gerar muitos grupos.
Compare snapshots
Uma comparação mostra crescimento e redução entre dois momentos.
antes = tracemalloc.take_snapshot()
executar_cenario()
depois = tracemalloc.take_snapshot()
for diferenca in depois.compare_to(antes, "lineno")[:10]:
print(diferenca)
Repita o cenário várias vezes para separar aquecimento de crescimento contínuo.
Baseline após aquecimento
Imports, caches de bytecode, pools e inicialização criam alocações legítimas.
Execute uma fase de warm-up, force o estado esperado e só então capture o snapshot de referência.
Detecte crescimento por repetição
for _ in range(5):
executar_cenario()
gc.collect()
snapshot = tracemalloc.take_snapshot()
registrar(snapshot)
O uso de gc.collect() em diagnóstico pode reduzir ruído, mas não representa necessariamente o comportamento normal de produção.
Filtros
Filter e DomainFilter incluem ou excluem traces.
filtros = [
tracemalloc.Filter(False, "<frozen importlib._bootstrap>"),
tracemalloc.Filter(False, "*/site-packages/*"),
]
filtrado = snapshot.filter_traces(filtros)
Não filtre cedo demais. Uma dependência externa pode ser a origem real do crescimento.
Filtros inclusivos e exclusivos
Um filtro exclusivo remove correspondências; um inclusivo mantém apenas correspondências compatíveis.
Documente os padrões usados para que relatórios possam ser reproduzidos.
Traceback de uma alocação
APIs de trace permitem inspecionar os frames registrados para blocos individuais.
Na prática, estatísticas agregadas costumam ser mais úteis do que listar milhões de traces.
Salve e carregue snapshots
Snapshots podem ser persistidos para análise posterior.
snapshot.dump("memoria.snap")
carregado = tracemalloc.Snapshot.load("memoria.snap")
O arquivo pode revelar paths e nomes internos. Proteja-o como artefato de diagnóstico.
Use linecache no relatório
O código-fonte das linhas pode ser recuperado para melhorar a saída.
import linecache
frame = estatistica.traceback[0]
linha = linecache.getline(frame.filename, frame.lineno).strip()
Consulte linecache no Python.
Inicie antes do import
Para rastrear alocações de startup, use opções do interpretador ou variável de ambiente suportada pela versão do Python.
Esse modo ajuda quando o crescimento acontece durante imports, mas produz mais ruído.
Overhead
Guardar traces para cada alocação consome CPU e memória. O custo cresce com o número de frames.
Em produção, use por janela curta, amostragem operacional controlada ou instância de diagnóstico.
Memória rastreada versus RSS
RSS pode continuar alto mesmo após objetos Python serem liberados, porque allocators mantêm arenas para reutilização e o sistema gerencia páginas.
Uma queda no valor rastreado sem queda no RSS não prova vazamento. Analise tendências e arquitetura do allocator.
Memória nativa
NumPy, bibliotecas de imagem, compressão, drivers e extensões C podem alocar fora do domínio visível.
Se RSS cresce mas tracemalloc permanece estável, use ferramentas nativas e métricas específicas da biblioteca.
Objetos vivos e referências
tracemalloc mostra onde memória foi alocada, não necessariamente por que o objeto continua vivo.
Combine com gc, inspeção de referências e análise de caches para descobrir ownership.
Leaks versus caches
Um cache pode crescer por design, mas sem limite se torna um vazamento operacional.
Verifique tamanho máximo, expiração, cardinalidade de chaves e política de remoção.
Threads
O rastreamento é global ao processo. Alocações de várias threads aparecem nos snapshots.
Inclua contexto de workload e sincronize o cenário de teste para comparar fases equivalentes.
Processos
Cada processo possui seu próprio estado de tracemalloc.
Em multiprocessing, colete snapshots ou métricas em cada worker e agregue fora do processo. Não confunda memória individual com total do serviço.
Testes de regressão
Um teste pode executar um cenário repetido e verificar que o crescimento líquido permanece abaixo de uma margem.
Evite limites rígidos demais: versão do Python, plataforma e imports alteram números. Compare tendências e use tolerância.
Measure uma função
def medir(funcao, *args, **kwargs):
tracemalloc.start(10)
try:
tracemalloc.reset_peak()
resultado = funcao(*args, **kwargs)
atual, pico = tracemalloc.get_traced_memory()
return resultado, atual, pico
finally:
tracemalloc.stop()
Não pare um tracing iniciado por outro componente. Coordene ownership.
clear_traces
clear_traces() remove traces registrados sem necessariamente alterar objetos vivos.
Use para iniciar uma fase limpa de diagnóstico, entendendo que você perde o histórico anterior.
stop
stop() desativa o rastreamento e limpa traces conforme a semântica da versão.
Após parar, snapshots anteriores ainda podem ser analisados como objetos independentes.
Relatórios úteis
Inclua arquivo, linha, código, tamanho, diferença, contagem e média. Mostre unidades legíveis, mas preserve bytes para cálculos.
Não despeje milhares de linhas; destaque os maiores crescimentos e permita drill-down.
Segurança e privacidade
Paths e linhas de código podem revelar nomes de clientes, diretórios internos e lógica proprietária.
Redija informações antes de anexar snapshots ou relatórios a tickets públicos.
Observabilidade
tracemalloc é melhor para diagnóstico do que como métrica contínua de alta frequência.
Use RSS, heap do processo, contagem de objetos e métricas de cache para monitoramento; ative snapshots quando a tendência indicar problema.
Testes
Teste um cenário estável, um crescimento intencional, liberação de objetos, cache limitado, múltiplas threads e workers separados.
Controle warm-up, force entradas determinísticas e repita para reduzir ruído.
Erros comuns
Os erros mais frequentes são confundir memória rastreada com RSS, capturar baseline antes do warm-up, usar apenas um snapshot, filtrar dependências cedo, ignorar alocações nativas, guardar frames demais em produção e concluir que todo crescimento é vazamento.
Conclusão
tracemalloc mostra onde o Python aloca memória e como o perfil muda ao longo do tempo. Use snapshots comparáveis, filtros documentados, picos por fase e cenários repetidos.
Combine resultados com RSS, garbage collector e métricas de bibliotecas nativas. Consulte a documentação oficial de tracemalloc, linecache no Python e o artigo sobre vazamentos de memória.







