J'ai écrit un programme Python qui agit sur un gros fichier d'entrée pour créer quelques millions d'objets représentant des triangles. L'algorithme est:
- lire un fichier d'entrée
- traiter le fichier et créer une liste de triangles, représentés par leurs sommets
- sortie des sommets au format OFF: une liste de sommets suivie d'une liste de triangles. Les triangles sont représentés par des indices dans la liste des sommets
L'exigence de OFF que j'imprime la liste complète des sommets avant d'imprimer les triangles signifie que je dois conserver la liste des triangles en mémoire avant d'écrire la sortie dans un fichier. En attendant, je reçois des erreurs de mémoire en raison de la taille des listes.
Quelle est la meilleure façon de dire à Python que je n'ai plus besoin de certaines données et qu'elles peuvent être libérées?
python
memory
memory-management
Nathan Fellman
la source
la source
Réponses:
Selon la documentation officielle de Python , vous pouvez forcer le garbage collector à libérer de la mémoire non référencée avec
gc.collect()
. Exemple:la source
gc.collect()
vous appeler à la fin d'une boucle peut éviter de fragmenter la mémoire, ce qui contribue à maintenir les performances. J'ai vu cela faire une différence significative (~ 20% d'exécution IIRC)gc.collect()
après le chargement d'une trame de données pandas à partir de hdf5 (500 000 lignes) a réduit l'utilisation de la mémoire de 1,7 Go à 500 Model my_array
suivie pargc.collect()
après le traitement du tableau est le seul moyen de libérer la mémoire et mon processus survit pour charger le tableau suivant.Malheureusement (en fonction de votre version et de la version de Python) certains types d'objets utilisent des "listes gratuites" qui sont une optimisation locale soignée mais peuvent provoquer une fragmentation de la mémoire, en particulier en faisant de plus en plus de mémoire "réservée" uniquement aux objets d'un certain type et ainsi indisponible pour le "fonds général".
La seule manière vraiment fiable de garantir qu'une utilisation importante mais temporaire de la mémoire renvoie toutes les ressources au système une fois terminée, est de faire en sorte que cette utilisation se produise dans un sous-processus, ce qui fait que le travail gourmand en mémoire se termine. Dans de telles conditions, le système d'exploitation fera son travail et recyclera volontiers toutes les ressources que le sous-processus peut avoir englouties. Heureusement, le
multiprocessing
module rend ce genre d'opération (qui était plutôt pénible) pas trop mal dans les versions modernes de Python.Dans votre cas d'utilisation, il semble que la meilleure façon pour les sous-processus d'accumuler certains résultats tout en s'assurant que ces résultats sont disponibles pour le processus principal est d'utiliser des fichiers semi-temporaires (par semi-temporaires, je veux dire, PAS le type de fichiers qui disparaissent automatiquement lorsqu'ils sont fermés, seuls les fichiers ordinaires que vous supprimez explicitement lorsque vous en avez terminé).
la source
multiprocessing.Manager
plutôt que des fichiers pour implémenter l'état partagé.La
del
déclaration pourrait être utile, mais IIRC il n'est pas garanti de libérer la mémoire . Les documents sont ici ... et une raison pour laquelle il n'est pas publié est ici .J'ai entendu des gens sur des systèmes de type Linux et Unix bifurquer un processus python pour faire du travail, obtenir des résultats puis le tuer.
Cet article contient des notes sur le garbage collector Python, mais je pense que le manque de contrôle de la mémoire est l'inconvénient de la mémoire gérée
la source
Python est récupéré, si vous réduisez la taille de votre liste, il récupérera de la mémoire. Vous pouvez également utiliser l'instruction "del" pour vous débarrasser complètement d'une variable:
la source
Vous ne pouvez pas libérer explicitement de la mémoire. Ce que vous devez faire est de vous assurer de ne pas conserver de références aux objets. Ils seront ensuite récupérés, libérant ainsi la mémoire.
Dans votre cas, lorsque vous avez besoin de grandes listes, vous devez généralement réorganiser le code, en utilisant généralement des générateurs / itérateurs à la place. De cette façon, vous n'avez pas du tout besoin d'avoir les grandes listes en mémoire.
http://www.prasannatech.net/2009/07/introduction-python-generators.html
la source
(
del
peut être votre ami, car il marque les objets comme pouvant être supprimés lorsqu'il n'y a aucune autre référence à eux. Maintenant, souvent, l'interpréteur CPython conserve cette mémoire pour une utilisation ultérieure, de sorte que votre système d'exploitation peut ne pas voir la mémoire "libérée".)Peut-être que vous ne rencontriez pas de problème de mémoire en premier lieu en utilisant une structure plus compacte pour vos données. Ainsi, les listes de nombres sont beaucoup moins efficaces en mémoire que le format utilisé par le
array
module standard ou lenumpy
module tiers . Vous économiseriez de la mémoire en plaçant vos sommets dans un tableau NumPy 3xN et vos triangles dans un tableau à N éléments.la source
del
ne fait rien qui ne réattribue simplement une valeur différente à tous les noms référençant un objet.del
libère la mémoire du point de vue de Python, mais généralement pas du point de vue de la bibliothèque d'exécution C ou du système d'exploitation. Références: stackoverflow.com/a/32167625/4297 , effbot.org/pyfaq/… .del
est tout aussi efficace avec les sorties hors champ, les réaffectations, etc.J'ai eu un problème similaire en lisant un graphique à partir d'un fichier. Le traitement comprenait le calcul d'une matrice flottante de 200 000 x 200 000 (une ligne à la fois) qui ne tenait pas en mémoire. Essayer de libérer de la mémoire entre les calculs en utilisant
gc.collect()
fixe l'aspect lié à la mémoire du problème, mais cela a entraîné des problèmes de performances: je ne sais pas pourquoi, mais même si la quantité de mémoire utilisée est restée constante, chaque nouvel appel agc.collect()
pris plus de temps que le précédent. Donc, assez rapidement, la collecte des ordures a pris la plupart du temps de calcul.Pour résoudre à la fois les problèmes de mémoire et de performances, je suis passé à l'utilisation d'une astuce multithreading que j'ai lue une fois quelque part (je suis désolé, je ne trouve plus le message correspondant). Avant, je lisais chaque ligne du fichier dans une grande
for
boucle, le traitais et l'exécutais degc.collect()
temps en temps pour libérer de l'espace mémoire. Maintenant, j'appelle une fonction qui lit et traite une partie du fichier dans un nouveau thread. Une fois le thread terminé, la mémoire est automatiquement libérée sans l'étrange problème de performances.Pratiquement, cela fonctionne comme ceci:
la source
D'autres ont publié des moyens de "persuader" l'interpréteur Python de libérer la mémoire (ou d'éviter autrement des problèmes de mémoire). Il y a de fortes chances que vous essayiez d'abord leurs idées. Cependant, je pense qu'il est important de vous donner une réponse directe à votre question.
Il n'y a vraiment aucun moyen de dire directement à Python de libérer de la mémoire. Le fait est que si vous voulez un niveau de contrôle aussi bas, vous devrez écrire une extension en C ou C ++.
Cela dit, il existe des outils pour vous aider:
la source
Si vous ne vous souciez pas de la réutilisation des sommets, vous pouvez avoir deux fichiers de sortie - un pour les sommets et un pour les triangles. Ajoutez ensuite le fichier triangle au fichier vertex lorsque vous avez terminé.
la source