tracemalloc no Python: encontre vazamentos

Publicado em: 15/08/2026
Tempo de leitura: 6 minutos
Desenvolvedor analisando consumo de memória com tracemalloc no Python

O módulo tracemalloc no Python ajuda a descobrir onde um programa está alocando memória. Ele registra rastros das alocações feitas pelo interpretador e permite comparar snapshots para identificar crescimento inesperado, objetos persistentes e trechos de código que merecem investigação. É uma ferramenta especialmente útil em APIs, workers, rotinas de dados e aplicações de longa duração.

Um aumento de memória nem sempre é um vazamento. O processo pode manter caches legítimos, estruturas globais, buffers ou pools internos. Por isso, o objetivo do tracemalloc não é apenas mostrar que a memória cresceu, mas revelar quais linhas e módulos contribuíram para esse crescimento.

Como o tracemalloc funciona

Quando o rastreamento é ativado, o Python registra a origem de cada bloco de memória acompanhado pelo alocador do interpretador. Cada registro pode incluir o arquivo, a linha e uma pilha curta de chamadas. Depois, o programa coleta snapshots e calcula estatísticas.

import tracemalloc

tracemalloc.start()

dados = [str(numero) for numero in range(100_000)]

snapshot = tracemalloc.take_snapshot()
for item in snapshot.statistics('lineno')[:10]:
    print(item)

O agrupamento por lineno mostra as linhas que concentram mais memória rastreada. Também é possível agrupar por arquivo ou traceback.

Inicie o rastreamento cedo

Para capturar importações, inicialização de caches e configuração de frameworks, ative o tracemalloc no começo do processo. Você pode chamar tracemalloc.start() no código ou usar a variável de ambiente PYTHONTRACEMALLOC.

PYTHONTRACEMALLOC=10 python app.py

O número define quantos frames serão armazenados em cada traceback. Mais frames oferecem contexto, mas aumentam o custo de memória e CPU.

Compare snapshots

A técnica mais útil é capturar um snapshot de referência, executar a operação suspeita e capturar outro snapshot.

import tracemalloc

tracemalloc.start(10)
antes = tracemalloc.take_snapshot()

for _ in range(50):
    processar_lote()

depois = tracemalloc.take_snapshot()

for diferenca in depois.compare_to(antes, 'lineno')[:20]:
    print(diferenca)

O resultado mostra a variação de tamanho, a quantidade de blocos e a localização associada. Crescimento repetido na mesma linha merece atenção.

Crie um cenário reproduzível

Diagnósticos de memória são mais confiáveis quando a carga é controlada. Execute a mesma operação várias vezes, use dados semelhantes e evite misturar deploy, importações e aquecimento da aplicação com a medição principal.

Em uma API, por exemplo, aqueça rotas e conexões antes do snapshot inicial. Em um worker, processe alguns lotes para estabilizar pools e caches.

Filtre ruído

Snapshots incluem alocações de bibliotecas, testes e infraestrutura. Use filtros para concentrar a análise no seu projeto.

filtros = [
    tracemalloc.Filter(True, '*/meu_projeto/*'),
    tracemalloc.Filter(False, '*/site-packages/*'),
]

snapshot_filtrado = snapshot.filter_traces(filtros)

Filtros inclusivos e exclusivos podem ser combinados. Confirme os caminhos reais no ambiente, pois containers e ambientes virtuais alteram os prefixos.

Agrupe por traceback

O agrupamento por traceback mostra a sequência de chamadas que levou à alocação. Isso ajuda quando a mesma função utilitária é chamada por rotas diferentes.

for estatistica in snapshot.statistics('traceback')[:5]:
    print(estatistica)
    for linha in estatistica.traceback.format():
        print(linha)

Use poucos frames inicialmente. Aumente a profundidade somente quando a linha final não fornecer contexto suficiente.

Meça a memória atual e o pico

get_traced_memory() retorna a memória atualmente rastreada e o pico desde o início.

atual, pico = tracemalloc.get_traced_memory()
print(f'atual={atual / 1024 / 1024:.2f} MB')
print(f'pico={pico / 1024 / 1024:.2f} MB')

O pico é útil para tarefas que liberam a memória ao final, mas consomem muito durante uma etapa intermediária.

Redefina o pico em operações isoladas

Use reset_peak() antes de uma etapa específica.

tracemalloc.reset_peak()
resultado = gerar_relatorio()
atual, pico = tracemalloc.get_traced_memory()

Isso não limpa as alocações nem reinicia o rastreamento. Apenas redefine a referência do pico.

Exemplo de crescimento acidental

historico = []

def registrar_evento(evento):
    historico.append(evento)

Uma lista global sem limite pode parecer inofensiva, mas cresce durante toda a vida do processo. O tracemalloc apontará a linha do append. A correção pode ser usar uma fila limitada, persistência externa ou política de expiração.

from collections import deque

historico = deque(maxlen=10_000)

Caches também precisam de limites

functools.lru_cache é seguro quando possui maxsize. Um cache ilimitado pode reter argumentos e resultados indefinidamente.

from functools import lru_cache

@lru_cache(maxsize=512)
def carregar_configuracao(chave):
    ...

Monitore cache_info() e limpe caches quando o ciclo de vida da aplicação exigir.

Referências mantidas por callbacks

Closures, listeners e callbacks podem manter objetos vivos. Um callback registrado em um objeto global pode capturar uma estrutura grande sem intenção. Examine registries, sinais, tarefas pendentes e handlers.

O artigo sobre weakref no Python mostra como referências fracas ajudam em caches e observadores.

Geradores e tarefas assíncronas

Geradores pausados mantêm seu frame e variáveis locais. Tarefas asyncio pendentes também podem reter contexto, exceções e buffers. Liste tarefas, verifique filas e confirme que cancelamentos são aguardados.

Para contexto assíncrono isolado, consulte contextvars no Python.

Tracebacks e exceções

Guardar exceções por muito tempo pode manter frames e variáveis locais vivos. Evite armazenar objetos de exceção completos em listas globais. Prefira serializar as informações necessárias.

Veja também traceback no Python para registrar pilhas sem reter memória desnecessariamente.

Arquivos temporários e buffers

Leituras com read() podem carregar arquivos inteiros. Prefira streaming e blocos quando o volume é grande. O guia de tempfile no Python mostra padrões seguros para arquivos temporários.

Tracemalloc não mede tudo

O módulo acompanha principalmente alocações feitas pelo gerenciador de memória do Python. Memória nativa usada por extensões C, bibliotecas numéricas, drivers ou processos filhos pode não aparecer por completo.

Compare os dados com a memória residente do processo, métricas do sistema operacional e ferramentas específicas. Em aplicações NumPy, por exemplo, buffers nativos podem dominar o consumo.

Use ferramentas complementares

Combine tracemalloc com métricas de RSS, perfis de objetos, logs e testes de carga. A documentação oficial do tracemalloc descreve snapshots, filtros e tracebacks. O guia de gerenciamento de memória do CPython explica os alocadores internos.

Salve snapshots para análise posterior

snapshot.dump('/tmp/memoria.snapshot')

carregado = tracemalloc.Snapshot.load('/tmp/memoria.snapshot')

Isso permite comparar execuções, mas trate o arquivo como dado interno. Ele pode revelar caminhos e estrutura do projeto.

Teste regressões de memória

Você pode criar testes que executam uma operação repetidamente e verificam se o crescimento permanece dentro de uma margem.

def testar_crescimento_controlado():
    tracemalloc.start()
    antes = tracemalloc.take_snapshot()

    for _ in range(100):
        executar_fluxo()

    depois = tracemalloc.take_snapshot()
    crescimento = sum(
        item.size_diff
        for item in depois.compare_to(antes, 'filename')
    )

    assert crescimento < 5 * 1024 * 1024

Evite limites rígidos demais, pois versões do Python e bibliotecas alteram padrões de alocação. Use o teste como sinal de regressão, não como prova absoluta.

Cuidados em produção

O rastreamento possui overhead. Ative por janela limitada, em uma réplica de diagnóstico ou com profundidade pequena. Não deixe snapshots frequentes acumularem memória. Remova dados temporários e desative com tracemalloc.stop() quando terminar.

Checklist de investigação

  • Reproduza a carga em ambiente controlado.
  • Aqueça a aplicação antes do snapshot inicial.
  • Compare snapshots com o mesmo agrupamento.
  • Filtre bibliotecas sem relação com o problema.
  • Examine caches, listas globais e registries.
  • Verifique tarefas, geradores e exceções retidas.
  • Compare com RSS e memória nativa.
  • Valide a correção com nova execução.

Conclusão

O tracemalloc no Python transforma suspeitas de vazamento em evidências concretas. Ao comparar snapshots, filtrar ruído e investigar as linhas que mais crescem, você consegue separar caches legítimos de retenções acidentais.

Use a ferramenta junto com métricas do sistema e testes reproduzíveis. O resultado é um diagnóstico mais rápido, correções mais seguras e aplicações de longa duração com consumo de memória previsível.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Conteúdo do artigo

    Artigos relacionados

    Código com anotações de tipos representando introspecção com annotationlib no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    annotationlib no Python: leia anotações

    Aprenda annotationlib no Python 3.14 para ler anotações como valores, ForwardRef ou strings e evitar riscos de execução.

    Ler mais

    Tempo de leitura: 7 minutos
    14/08/2026
    Arquivadores organizados representando módulos importados diretamente de arquivos ZIP com zipimport no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    zipimport no Python: importe de ZIPs

    Aprenda zipimport no Python para importar módulos e pacotes de arquivos ZIP, trabalhar com loaders e evitar riscos de segurança.

    Ler mais

    Tempo de leitura: 6 minutos
    14/08/2026
    Diagrama de diretórios representando caminhos site-packages e configuração do módulo site no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    site no Python: entenda os caminhos

    Aprenda o módulo site no Python para entender site-packages, user site, arquivos .pth, sitecustomize, usercustomize e opções de inicialização.

    Ler mais

    Tempo de leitura: 8 minutos
    14/08/2026
    Ícone de instalador representando o bootstrap offline do pip com ensurepip no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    ensurepip no Python: reinstale o pip

    Aprenda ensurepip no Python para instalar ou restaurar o pip offline, escolher ambiente, scripts, upgrade e evitar conflitos com o

    Ler mais

    Tempo de leitura: 7 minutos
    14/08/2026
    Caixa de software representando metadados de pacotes consultados com importlib.metadata no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    importlib.metadata no Python: pacotes

    Aprenda importlib.metadata no Python para consultar versões, dependências, arquivos, metadados e entry points de pacotes instalados.

    Ler mais

    Tempo de leitura: 7 minutos
    14/08/2026
    Código em execução representando módulos e caminhos executados com runpy no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    runpy no Python: execute módulos

    Aprenda runpy no Python para executar módulos, scripts, diretórios e arquivos ZIP, controlar namespaces e evitar problemas de segurança e

    Ler mais

    Tempo de leitura: 6 minutos
    13/08/2026