web-dev-qa-db-fra.com

Collecte de déchets Python

J'ai créé du code python qui crée un objet dans une boucle et, à chaque itération, écrase cet objet avec un nouvel objet du même type. Cette opération est effectuée 10 000 fois et Python occupe 7 Mo de mémoire toutes les secondes jusqu'à ce que ma 3 Go RAM soit utilisée. Est-ce que quelqu'un connaît un moyen de supprimer les objets de la mémoire?

35
utdiscant

Vous n'avez pas fourni suffisamment d'informations. Cela dépend des spécificités de l'objet que vous créez et de ce que vous en faites d'autre dans la boucle. Si l'objet ne crée pas de références circulaires, il devrait être désalloué à la prochaine itération. Par exemple, le code

for x in range(100000):
  obj = " " * 10000000

n'entraînera pas une allocation de mémoire toujours croissante.

19
Vinay Sajip

Je pense que ceci est une référence circulaire (bien que la question ne soit pas explicite à propos de cette information.)

Un moyen de résoudre ce problème consiste à appeler manuellement la récupération de place. Lorsque vous exécutez manuellement Garbage Collector, il balayera également les objets référencés circulaires.

import gc

for i in xrange(10000):
    j = myObj()
    processObj(j)
    #assuming count reference is not zero but still
    #object won't remain usable after the iteration

    if !(i%100):
        gc.collect()

Dans ce cas, n’exécutez pas trop souvent le ramasse-miettes car il a sa propre surcharge, par exemple. Si vous exécutez un ramasse-miettes dans chaque boucle, l'interprétation deviendra extrêmement lente.

23
hasanatkazmi

Ceci est une ancienne erreur qui a été corrigée pour certains types dans Python 2.5. Ce qui se passait, c’est que le python n’était pas très doué pour collecter des objets tels que des listes vides/dictionnaires/tupes/floats/ints. En python 2.5, cela était corrigé ... principalement. Cependant, les floats et les ints sont des singletons pour les comparaisons, donc une fois qu’un de ceux-ci est créé, il reste aussi longtemps que l’interprète est en vie. J'ai été piqué par ce pire face à une grande quantité de flotteurs, car ils ont la mauvaise habitude d'être uniques. Cela a été caractérisé pour python 2.4 et mis à jour à propos de son pliage dans python 2.5

Le meilleur moyen que j'ai trouvé est de passer à python 2.5 ou plus récent pour résoudre le problème des listes/dictionnaires/tuples. Pour les nombres, la seule solution est de ne pas laisser de grandes quantités de nombres entrer en python. Je l'ai fait avec mon propre wrapper à un objet c ++, mais j'ai l'impression que numpy.array donnera des résultats similaires.

En tant que post script, je n'ai aucune idée de ce qu'il est advenu de cela dans Python 3, mais je soupçonne que les nombres font toujours partie d'un singleton. La fuite de mémoire est donc une caractéristique de la langue.

13
Pete Peterson

Si vous créez des références circulaires, vos objets ne seront pas désalloués immédiatement, mais devront attendre l'exécution d'un cycle CPG.

Vous pouvez utiliser le module faibleref pour résoudre ce problème ou supprimer explicitement vos objets après utilisation.

6
Algorias

J'ai constaté que dans mon cas (avec Python 2.5.1), avec des références circulaires impliquant des classes utilisant des méthodes __del__(), non seulement le garbage collection ne se produisait-il pas à temps, mais que les méthodes __del__() de mes objets n'étaient jamais appelées, même lorsque le script est sorti. J'ai donc utilisé faiblesref pour casser les références circulaires et tout allait bien.

Félicitations à Miles qui a fourni toutes les informations dans ses commentaires pour que je puisse mettre cela ensemble.

3
Von

Voici une chose que vous pouvez faire sur le REPL pour forcer le déréférencement d'une variable:

>>> x = 5
>>> x
5
>>> del x
>>> x
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined
1
Mark Rushakoff

faiblesref peut être utilisé pour du code structuré à objets circulaires comme dans l’exemple expliqué

0
alkanschtein