Caza de fugas de memoria en aplicaciones Python

Wai Chee Yau

Sigue

Feb 13, 2019 – 4 min read

En Zendesk utilizamos bastante Python para construir productos de aprendizaje automático (ML). Uno de los problemas comunes de rendimiento que encontramos con las aplicaciones de aprendizaje automático son las fugas y los picos de memoria. El código Python suele ejecutarse dentro de contenedores a través de marcos de procesamiento distribuido como Hadoop, Spark y AWS Batch. A cada contenedor se le asigna una cantidad fija de memoria. Una vez que la ejecución del código excede el límite de memoria especificado, el contenedor terminará debido a errores de memoria.

Una solución rápida es aumentar la asignación de memoria. Sin embargo, esto puede resultar en un desperdicio de recursos y afectar la estabilidad de los productos debido a picos de memoria impredecibles. Las causas de las fugas de memoria pueden incluir:

  • literación de objetos grandes que no se liberan
  • ciclos de referencia dentro del código
  • bibliotecas subyacentes/extensiones que pierden memoria

Un ejercicio útil es perfilar el uso de memoria de las aplicaciones para obtener una mejor comprensión sobre la eficiencia del espacio del código y los paquetes subyacentes utilizados. Este post cubre:

  • perfilando el uso de la memoria de la aplicación a través del tiempo
  • cómo inspeccionar el uso de la memoria en una parte específica del programa
  • consejos para depurar problemas de memoria

Puedes mirar el uso de la memoria variando a través del tiempo durante la ejecución del código Python usando el paquete memory-profile.

# install the required packages
pip install memory_profiler
pip install matplotlib# run the profiler to record the memory usage
# sample 0.1s by defaut
mprof run --include-children python fantastic_model_building_code.py# plot the recorded memory usage
mprof plot --output memory-profile.png

A. Perfil de memoria en función del tiempo

La opción include-children incluirá el uso de memoria de cualquier proceso hijo engendrado a través del proceso padre. El gráfico A muestra un proceso iterativo de entrenamiento del modelo que hace que la memoria aumente en ciclos a medida que se procesan los lotes de datos de entrenamiento. Los objetos se liberan una vez que la recolección de basura se pone en marcha.

Si el uso de la memoria está creciendo constantemente, hay un problema potencial de fugas de memoria. Aquí hay un ejemplo de script para ilustrar esto.

B. Huellas de memoria que aumentan a través del tiempo

Se puede establecer un punto de interrupción del depurador una vez que el uso de la memoria excede cierto umbral utilizando la opción pdb-mmem que es útil para la solución de problemas.

Volcado de memoria en un momento dado

Es importante entender el número esperado de objetos grandes en el programa y si deben ser duplicados y/o transformados a diferentes formatos.

Para analizar más a fondo los objetos en memoria, se puede crear un volcado de heap durante ciertas líneas del código en el programa con muppy.

Ejemplo de resumen de volcado de memoria heap

Otra librería de perfilado de memoria útil es objgraph que puede generar gráficos de objetos para inspeccionar el linaje de los mismos.

Esfuércese por conseguir un bucle de retroalimentación rápido

Un enfoque útil es crear un pequeño «caso de prueba» que ejecute sólo el código de fuga de memoria en cuestión. Considere la posibilidad de utilizar un subconjunto de los datos muestreados aleatoriamente si los datos de entrada completos son largos de ejecutar.

Ejecutar las tareas intensivas de memoria en un proceso separado

Python no necesariamente libera la memoria inmediatamente de vuelta al sistema operativo. Para asegurarse de que la memoria se libera después de que una pieza de código se ha ejecutado, es necesario ejecutar en un proceso separado. Esta página proporciona más detalles sobre la recolección de basura de Python.

El depurador puede añadir referencias a objetos

Si se utiliza un depurador de puntos de interrupción como pdb, cualquier objeto creado y referenciado manualmente desde el depurador permanecerá en el perfil de memoria. Esto puede crear una falsa sensación de fugas de memoria donde los objetos no se liberan de manera oportuna.

Cuidado con los paquetes que pueden tener fugas

Algunas bibliotecas de Python podrían tener potencialmente fugas de memoria. Por ejemplo, pandas tiene bastantes problemas conocidos de fugas de memoria.

¡Feliz caza!

Deja una respuesta

Tu dirección de correo electrónico no será publicada.