2010-07-30 3 views
6

Je me bats contre une fuite de mémoire dans un projet Python et y passais déjà beaucoup de temps. J'ai déduit le problème à un petit exemple. Maintenant, semble que je connais la solution, mais je ne peux pas comprendre pourquoi.Pourquoi l'affectation de tranches de liste python consomme de la mémoire?

import random 

def main(): 
    d = {} 
    used_keys = [] 
    n = 0 
    while True: 
     # choose a key unique enough among used previously 
     key = random.randint(0, 2 ** 60) 
     d[key] = 1234 # the value doesn't matter 
     used_keys.append(key) 
     n += 1 
     if n % 1000 == 0: 
      # clean up every 1000 iterations 
      print 'thousand' 
      for key in used_keys: 
       del d[key] 
       used_keys[:] = [] 
       #used_keys = [] 

if __name__ == '__main__': 
    main() 

L'idée est que je stocke des valeurs dans le dict d et de mémoriser les clés utilisées dans une liste pour pouvoir nettoyer le dict de temps en temps.

Cette variante du programme mange avec confiance de la mémoire ne jamais le renvoyer. Si j'utilise une méthode alternative pour "effacer" used_keys qui est commentée dans l'exemple, tout va bien: la consommation de mémoire reste à un niveau constant.

Pourquoi?

Testé sur CPython et de nombreux linux.

+0

Comment savez-vous avec certitude qu'il ne le retourne jamais? Il se peut que le système d'exploitation ne le demande jamais. – detly

+2

Ne devrait-il pas effacer 'used_keys' en dehors de la boucle' for key in used_keys'? – adamk

+2

> L'idée est que je stocke certaines valeurs dans la dictée et mémorise les clés utilisées dans une liste pour pouvoir nettoyer la dict de temps en temps. Pourquoi ne pas utiliser 'd.keys()'? Ce sera la même liste de clés. –

Répondre

5

Voici la raison - la méthode actuelle ne supprime pas les clés de la dict (une seule, en fait). C'est parce que vous effacez la liste used_keys pendant la boucle, et la boucle se termine prématurément.

La méthode 2 (commentée) fonctionne cependant lorsque vous attribuez une nouvelle valeur à used_keys afin que la boucle se termine avec succès.

Voir la différence entre:

>>> a=[1,2,3] 
>>> for x in a: 
... print x 
... a=[] 
... 
1 
2 
3 

et

>>> a=[1,2,3] 
>>> for x in a: 
... print x 
... a[:] = [] 
... 
1 
>>> 
+1

Ah !! Je suis stupide, stupide, stupide. J'étais si heureux de reconstruire la fuite de mémoire dans un petit extrait ... C'est une erreur triste, bien sûr. Ça ne représente pas mon problème, je vais continuer à chasser. Mais vous avez raison avec la réponse à la question initiale. Merci! – nkrkv

0

Pourquoi pas quelque chose comme ce travail?

from itertools import count 
import uuid 

def main(): 
    d = {} 
    for n in count(1): 
     # choose a key unique enough among used previously 
     key = uuid.uuid1() 
     d[key] = 1234 # the value doesn't matter 
     if n % 1000 == 0: 
      # clean up every 1000 iterations 
      print 'thousand' 
      d.clear() 

if __name__ == '__main__': 
    main() 
Questions connexes