La chasse aux fuites de mémoire dans les applications Python

Wai Chee Yau

Follow

Feb 13, 2019 – 4 min lu

Nous utilisons Python assez souvent chez Zendesk pour construire des produits d’apprentissage automatique (ML). L’un des problèmes de performance courants que nous avons rencontrés avec les applications d’apprentissage automatique est celui des fuites et des pics de mémoire. Le code Python est généralement exécuté dans des conteneurs via des cadres de traitement distribué tels que Hadoop, Spark et AWS Batch. Chaque conteneur se voit allouer une quantité fixe de mémoire. Une fois que l’exécution du code dépasse la limite de mémoire spécifiée, le conteneur se termine en raison d’erreurs de mémoire.

Une solution rapide consiste à augmenter l’allocation de mémoire. Cependant, cela peut entraîner un gaspillage de ressources et affecter la stabilité des produits en raison de pics de mémoire imprévisibles. Les causes des fuites de mémoire peuvent inclure :

  • linguer de gros objets qui ne sont pas libérés
  • des cycles de référence dans le code
  • des bibliothèques sous-jacentes/des extensions qui fuient la mémoire

Un exercice utile est de profiler l’utilisation de la mémoire des applications pour avoir une meilleure compréhension sur l’efficacité de l’espace du code et des paquets sous-jacents utilisés. Ce post couvre:

  • profilage de l’utilisation de la mémoire de l’application à travers le temps
  • comment inspecter l’utilisation de la mémoire à une partie spécifique du programme
  • trucs pour déboguer les problèmes de mémoire

Vous pouvez regarder l’utilisation de la mémoire variant à travers le temps pendant l’exécution du code Python en utilisant le paquet 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. Profil de mémoire en fonction du temps

L’option include-children inclura l’utilisation de la mémoire de tous les processus enfants engendrés via le processus parent. Le graphique A montre un processus itératif de formation de modèle qui entraîne une augmentation de la mémoire par cycles au fur et à mesure que les lots de données de formation sont traités. Les objets sont libérés une fois que la collecte des ordures entre en jeu.

Si l’utilisation de la mémoire augmente constamment, il y a un problème potentiel de fuites de mémoire. Voici un exemple de script factice pour illustrer cela.

B. Empreintes mémoire augmentant au fil du temps

Un point d’arrêt du débogueur peut être défini une fois que l’utilisation de la mémoire dépasse un certain seuil en utilisant l’option pdb-mmem qui est pratique pour le dépannage.

Dump de mémoire à un moment donné

Il est important de comprendre le nombre attendu de gros objets dans le programme et s’ils doivent être dupliqués et/ou transformés en différents formats.

Pour analyser davantage les objets en mémoire, un heap dump peut être créé pendant certaines lignes de code du programme avec muppy.

Exemple de résumé de vidage de tas de mémoire

Une autre bibliothèque de profilage de mémoire utile est objgraph qui peut générer des graphes d’objets pour inspecter le lignage des objets.

S’efforcer d’obtenir une boucle de rétroaction rapide

Une approche utile consiste à créer un petit « cas de test » qui exécute uniquement le code de fuite de mémoire en question. Envisagez d’utiliser un sous-ensemble des données échantillonnées au hasard si les données d’entrée complètes sont longues à exécuter.

Exécuter les tâches gourmandes en mémoire dans un processus séparé

Python ne libère pas nécessairement la mémoire immédiatement en retour au système d’exploitation. Pour s’assurer que la mémoire est libérée après l’exécution d’un morceau de code, celui-ci doit être exécuté dans un processus séparé. Cette page fournit plus de détails sur la collecte des déchets de Python.

Le débogueur peut ajouter des références à des objets

Si un débogueur à point d’arrêt tel que pdb est utilisé, tout objet créé et référencé manuellement à partir du débogueur restera dans le profil de mémoire. Cela peut créer un faux sentiment de fuites de mémoire où les objets ne sont pas libérés en temps opportun.

Faites attention aux paquets qui peuvent être fuyants

Certaines bibliothèques Python pourraient potentiellement avoir des fuites de mémoire. Par exemple, pandas a pas mal de problèmes connus de fuites de mémoire.

Happy hunting!

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée.