17 votes

Puis-je découvrir la demande d'allocation qui a causé mon MemoryError Python ?

Contexte

Mon petit script Python utilise une bibliothèque pour travailler sur des données relativement importantes. L'algorithme standard pour cette tâche est un algorithme de programmation dynamique, donc vraisemblablement la bibliothèque "sous le capot" alloue un grand tableau pour suivre les résultats partiels de la programmation dynamique. En effet, lorsque j'essaie de lui donner une entrée assez grande, il donne immédiatement une MemoryError.

Idéalement, sans plonger dans les profondeurs de la bibliothèque, je veux savoir s'il vaut la peine d'essayer cet algorithme sur une machine différente avec plus de mémoire, ou d'essayer de réduire un peu la taille de mon entrée, ou si c'est une cause perdue pour la taille des données que j'essaie d'utiliser.

Question

Lorsque mon code Python lance une MemoryError, y a-t-il un moyen "top-down" pour moi d'investiguer quelle était la taille de la mémoire que mon code a essayé d'allouer ce qui a causé l'erreur, par exemple en inspectant l'objet d'erreur?

4voto

Martijn Pieters Points 271458

Vous ne pouvez pas voir à partir de l'exception MemoryError, et l'exception est soulevée pour n'importe quelle situation où l'allocation de mémoire a échoué, y compris les éléments internes de Python qui ne se connectent pas directement au code créant de nouvelles structures de données Python; certains modules créent des verrous ou d'autres objets de support et ces opérations peuvent échouer en raison de l'épuisement de la mémoire.

Vous ne pouvez pas non plus savoir exactement combien de mémoire serait nécessaire pour que l'opération réussisse. Si la bibliothèque crée plusieurs structures de données au cours de l'opération, essayer d'allouer de la mémoire pour une chaîne utilisée comme clé de dictionnaire pourrait être la goutte d'eau qui fait déborder le vase, ou cela pourrait être la copie de toute la structure de données existante pour mutation, ou autre chose, mais cela ne dit rien sur la quantité de mémoire qui sera nécessaire pour le reste du processus.

Cela étant dit, Python peut vous donner des informations détaillées sur les allocations de mémoire effectuées, et quand, et où, en utilisant le module tracemalloc. En utilisant ce module et une approche expérimentale, vous pourriez estimer combien de mémoire votre jeu de données nécessiterait pour être complet.

Le truc consiste à trouver des ensembles de données pour lesquels le processus peut être terminé. Vous voudriez trouver des ensembles de données de différentes tailles, et vous pourriez alors mesurer combien de mémoire ces structures de données nécessitent. Vous créer des instantanés avant et après avec tracemalloc.take_snapshot(), comparer les différences et les statistiques entre les instantanés pour ces ensembles de données, et peut-être pourriez-vous extrapoler à partir de ces informations combien de mémoire supplémentaire votre jeu de données plus grand aurait besoin. Cela dépend, bien sûr, de la nature de l'opération et des ensembles de données, mais s'il y a un type de modèle quelconque, tracemalloc est votre meilleur moyen pour le découvrir.

4voto

amirathi Points 86

Vous pouvez voir l'allocation de mémoire avec Pyampler mais vous devrez ajouter les déclarations de débogage localement dans la bibliothèque que vous utilisez. En supposant un package PyPi standard, voici les étapes :

  1. Clonez le package localement.

2 Utilisez le module de résumé de Pyampler. Placez ce qui suit à l'intérieur de la méthode de récursion principale,

   from pympler import summary
   def data_intensive_method(data_xyz)
       sum1 = summary.summarize(all_objects)
       summary.print_(sum1)
       ...
  1. Exécutez pip install -e . pour installer le package édité localement.
  2. Exécutez votre programme principal et vérifiez la console pour l'utilisation de la mémoire à chaque itération.

2voto

roeen30 Points 671

Il semble que MemoryError ne soit pas créée avec des données associées :

def crash():
    x = 32 * 10 ** 9
    return 'a' * x

try:
    crash()
except MemoryError as e:
    print(vars(e))  # affiche: {}

Cela a du sens - comment le pourrait-il s'il ne reste plus de mémoire ?

Je ne pense pas qu'il y ait une solution facile. Vous pouvez partir de la trace que MemoryError provoque et investiguer avec un débogueur ou utiliser un profileur de mémoire comme pympler (ou psutil comme suggéré dans les commentaires).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X