tracemalloc en Python: detecta fugas

Publicado el: 15/08/2026
Tempo de leitura: 6 minutos
Desarrollador investigando consumo de memoria con tracemalloc en Python

tracemalloc en Python permite descubrir dónde una aplicación asigna memoria. El módulo registra el origen de los bloques gestionados por el intérprete y permite comparar snapshots para localizar crecimiento inesperado, objetos retenidos y rutas de código que requieren investigación. Resulta especialmente útil en APIs, workers, procesos de datos y servicios que permanecen activos durante muchas horas.

Un aumento de memoria no siempre significa una fuga. El proceso puede mantener cachés, pools, buffers, módulos importados o índices globales de forma intencional. Por eso, tracemalloc no solo indica que la memoria creció: muestra qué archivos, líneas y pilas de llamadas contribuyeron al cambio.

Cómo funciona tracemalloc

Cuando el seguimiento está activo, Python registra el origen de cada bloque acompañado por su gestor de memoria. Cada traza puede incluir archivo, línea y una pila corta. Después se capturan snapshots y se agrupan las estadísticas.

import tracemalloc

tracemalloc.start()
valores = [str(numero) for numero in range(100_000)]
snapshot = tracemalloc.take_snapshot()

for dato in snapshot.statistics('lineno')[:10]:
    print(dato)

El agrupamiento por lineno destaca las líneas responsables de las mayores asignaciones rastreadas.

Activa el seguimiento al inicio

Si necesitas observar importaciones, inicialización del framework y construcción de cachés, inicia tracemalloc al comienzo del proceso. También puedes usar la variable PYTHONTRACEMALLOC.

PYTHONTRACEMALLOC=10 python app.py

El número determina cuántos frames se guardan por traza. Una profundidad mayor aporta contexto, pero consume más CPU y memoria.

Compara snapshots

El flujo más útil consiste en capturar una referencia, ejecutar varias veces la operación sospechosa y tomar otro snapshot.

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

for _ in range(50):
    procesar_lote()

despues = tracemalloc.take_snapshot()
for cambio in despues.compare_to(antes, 'lineno')[:20]:
    print(cambio)

La comparación muestra diferencia de tamaño, cantidad de bloques y ubicación. Un crecimiento repetido en la misma línea merece análisis.

Crea una carga reproducible

El diagnóstico es más fiable cuando la carga está controlada. Repite la misma operación con datos similares y evita mezclar despliegue, importaciones y calentamiento con la medición principal.

En una API, calienta rutas, serializadores y conexiones antes del snapshot inicial. En un worker, procesa algunos trabajos para estabilizar colas y cachés internas.

Filtra el ruido

Los snapshots incluyen código propio, bibliotecas, herramientas de prueba e infraestructura. Aplica filtros para concentrarte en el proyecto.

filtros = [
    tracemalloc.Filter(True, '*/mi_proyecto/*'),
    tracemalloc.Filter(False, '*/site-packages/*'),
]
filtrado = snapshot.filter_traces(filtros)

Comprueba los caminos reales del entorno, porque containers y entornos virtuales cambian los prefijos.

Agrupa por traceback

El agrupamiento por traceback muestra la secuencia de llamadas que produjo la asignación. Esto ayuda cuando una función auxiliar es utilizada por varias rutas.

for dato in snapshot.statistics('traceback')[:5]:
    print(dato)
    for linea in dato.traceback.format():
        print(linea)

Empieza con pocas capas y aumenta la profundidad solo si falta contexto.

Mide el uso actual y el pico

get_traced_memory() devuelve la memoria rastreada actualmente y el valor máximo observado desde el inicio.

actual, pico = tracemalloc.get_traced_memory()
print(actual / 1024 / 1024)
print(pico / 1024 / 1024)

El pico ayuda en tareas que liberan memoria al terminar, pero necesitan buffers grandes durante una fase intermedia.

Reinicia la referencia del pico

tracemalloc.reset_peak()
resultado = crear_informe()
actual, pico = tracemalloc.get_traced_memory()

Esto no elimina asignaciones ni reinicia el seguimiento. Solo redefine el máximo de referencia.

Colecciones globales sin límite

Un patrón frecuente es una lista global que crece durante toda la vida del proceso.

historial = []

def registrar(evento):
    historial.append(evento)

Tracemalloc señalará la línea del append. Puedes usar una cola limitada, almacenamiento externo o una política de expiración.

from collections import deque
historial = deque(maxlen=10_000)

Limita las cachés

Una caché ilimitada puede retener argumentos y resultados indefinidamente. Define un tamaño y observa su tasa de aciertos.

from functools import lru_cache

@lru_cache(maxsize=512)
def cargar_configuracion(clave):
    ...

Consulta cache_info() y limpia la caché cuando lo exija su ciclo de vida.

Callbacks que retienen objetos

Closures, listeners y callbacks pueden mantener estructuras grandes. Un callback registrado en un objeto global puede capturar datos sin intención. Revisa señales, registries, buses de eventos y futures pendientes.

La guía sobre weakref en Python explica cómo usar referencias débiles en cachés y observadores.

Generadores y tareas asíncronas

Los generadores suspendidos conservan frames y variables locales. Las tareas asyncio pendientes pueden retener contexto, excepciones, cuerpos de solicitud y buffers. Lista las tareas, inspecciona colas y espera correctamente las cancelaciones.

Para contexto asíncrono aislado, consulta contextvars en Python.

Excepciones y tracebacks

Guardar excepciones durante mucho tiempo puede preservar frames y variables locales. Evita almacenar objetos de excepción completos en listas globales. Serializa solo la información necesaria.

El artículo sobre traceback en Python muestra cómo registrar pilas sin retención innecesaria.

Lecturas grandes y buffers temporales

Una llamada a read() sin límite puede cargar un archivo completo. Prefiere streaming o bloques. Consulta tempfile en Python para patrones seguros con archivos temporales.

Tracemalloc no mide toda la memoria

El módulo rastrea principalmente asignaciones realizadas por el gestor de memoria de Python. La memoria nativa de extensiones C, bibliotecas numéricas, drivers o procesos hijos puede no aparecer completamente.

Compara los datos con RSS, métricas del sistema operativo y perfiles específicos. En cargas intensivas con NumPy, los buffers nativos pueden dominar el consumo.

Usa herramientas complementarias

Combina snapshots con métricas de proceso, logs, inspección de objetos y pruebas de carga. La documentación oficial de tracemalloc explica snapshots, filtros y trazas. La documentación de memoria de CPython describe sus asignadores.

Guarda snapshots

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

Los archivos permiten análisis posterior, pero pueden revelar rutas y estructura interna del proyecto. Trátalos como datos de diagnóstico.

Crea pruebas de regresión

Una prueba puede repetir una operación y verificar que el crecimiento permanece dentro de un margen razonable.

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

    for _ in range(100):
        ejecutar_flujo()

    despues = tracemalloc.take_snapshot()
    crecimiento = sum(
        dato.size_diff
        for dato in despues.compare_to(antes, 'filename')
    )
    assert crecimiento < 5 * 1024 * 1024

No uses umbrales demasiado rígidos, porque versiones distintas de Python y dependencias pueden cambiar los patrones de asignación.

Precauciones en producción

El seguimiento añade overhead. Actívalo durante una ventana limitada, en una réplica de diagnóstico o con poca profundidad. No acumules snapshots. Elimina archivos temporales y llama a tracemalloc.stop() al terminar.

Lista de comprobación

  • Reproduce la carga en condiciones controladas.
  • Calienta la aplicación antes de la referencia.
  • Compara snapshots con el mismo agrupamiento.
  • Filtra dependencias ajenas al problema.
  • Revisa cachés, colecciones globales y registries.
  • Inspecciona tareas, generadores y excepciones retenidas.
  • Compara memoria rastreada, RSS y memoria nativa.
  • Valida la corrección con otra ejecución.

Conclusión

tracemalloc en Python convierte una sospecha de fuga en evidencia útil. Las comparaciones de snapshots, los filtros y las pilas de asignación muestran qué líneas crecen y ayudan a diferenciar cachés legítimas de retenciones accidentales.

Úsalo junto con métricas del sistema y pruebas reproducibles. Así obtendrás diagnósticos más rápidos, correcciones seguras y servicios Python de larga duración con un consumo de memoria predecible.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Contenido del artículo

    Artículos relacionados

    Monitor con código binario que representa instrucciones opcode del bytecode de Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    opcode en Python: explora el bytecode

    Aprende opcode en Python para mapear instrucciones de bytecode, argumentos, saltos, caches y efectos de pila mediante dis.

    Ler mais

    Tempo de leitura: 5 minutos
    15/08/2026
    Código con anotaciones de tipos que representa introspección con annotationlib en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    annotationlib en Python: lee anotaciones

    Aprende annotationlib en Python 3.14 para recuperar anotaciones como valores, ForwardRef o strings y controlar riesgos de ejecución.

    Ler mais

    Tempo de leitura: 5 minutos
    14/08/2026
    Archivadores organizados que representan módulos importados directamente desde archivos ZIP con zipimport en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    zipimport en Python: importa desde ZIP

    Aprende zipimport en Python para cargar módulos y paquetes desde archivos ZIP, usar importadores y proteger sistemas de plugins.

    Ler mais

    Tempo de leitura: 5 minutos
    14/08/2026
    Diagrama de directorios que representa rutas site-packages y configuración del módulo site en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    site en Python: entiende las rutas

    Aprende el módulo site en Python para entender site-packages, user site, archivos .pth, sitecustomize, usercustomize y opciones de inicio.

    Ler mais

    Tempo de leitura: 7 minutos
    14/08/2026
    Icono de instalador que representa el bootstrap offline de pip con ensurepip en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    ensurepip en Python: restaura pip

    Aprende ensurepip en Python para instalar o restaurar pip sin internet, elegir entorno, scripts, upgrade y evitar conflictos con el

    Ler mais

    Tempo de leitura: 6 minutos
    14/08/2026
    Paquete de software que representa metadatos consultados con importlib.metadata en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    importlib.metadata en Python: paquetes

    Aprende importlib.metadata en Python para consultar versiones, dependencias, archivos, metadatos y entry points de paquetes instalados.

    Ler mais

    Tempo de leitura: 6 minutos
    14/08/2026