TL/DR :
import gc, sys
print len(gc.get_objects()) # 4073 objects in memory
# Attempt to unload the module
import httplib
del sys.modules["httplib"]
httplib = None
gc.collect()
print len(gc.get_objects()) # 6745 objects in memory
UPDATE J'ai contacté les développeurs de Python à propos de ce problème et, en effet, c'est il ne sera pas possible de décharger un module complètement "dans les cinq prochaines années". (voir le lien)
Veuillez accepter que Python ne supporte effectivement pas le déchargement des modules pour des problèmes techniques graves, fondamentaux, insurmontables, en 2.x.
Au cours de ma récente recherche d'une fuite de mémoire dans mon application, j'ai réduit le problème à des modules, à savoir mon incapacité à collecte des déchets un module non chargé. Utilisation de tout La méthode indiquée ci-dessous pour décharger un module laisse des milliers d'objets en mémoire. En d'autres termes, je ne peux pas décharger un module en Python...
Le reste de la question consiste à essayer de récupérer un module d'une manière ou d'une autre.
Essayons :
import gc
import sys
sm = sys.modules.copy() # httplib, which we'll try to unload isn't yet
# in sys.modules, so, this isn't the source of problem
print len(gc.get_objects()) # 4074 objects in memory
Enregistrons une copie de sys.modules
pour tenter de le restaurer plus tard. Il s'agit donc d'une base de référence de 4074 objets. Nous devrions idéalement y revenir d'une manière ou d'une autre.
Importons un module :
import httplib
print len(gc.get_objects()) # 7063 objects in memory
Nous en sommes à 7K objets non-déchets. Essayons de supprimer httplib
de sys.modules
.
sys.modules.pop('httplib')
gc.collect()
print len(gc.get_objects()) # 7063 objects in memory
Eh bien, ça n'a pas marché. Hmm, mais n'y a t-il pas une référence dans __main__
? Oh, oui :
del httplib
gc.collect()
print len(gc.get_objects()) # 6746 objects in memory
Hourra, moins 300 objets. Mais pas de cigare, ça fait bien plus que 4000 objets originaux. Essayons de restaurer sys.modules
de la copie.
sys.modules = sm
gc.collect()
print len(gc.get_objects()) # 6746 objects in memory
Hmmm, eh bien, c'était inutile, pas de changement... Peut-être que si on efface les globales...
globals().clear()
import gc # we need this since gc was in globals() too
gc.collect()
print len(gc.get_objects()) # 6746 objects in memory
des locaux ?
locals().clear()
import gc # we need this since gc was in globals() too
gc.collect()
print len(gc.get_objects()) # 6746 objects in memory
Et si et si on imported
un module à l'intérieur de exec
?
local_dict = {}
exec 'import httplib' in local_dict
del local_dict
gc.collect()
print len(gc.get_objects()) # back to 7063 objects in memory
Maintenant, ce n'est pas juste, il l'a importé en __main__
Pourquoi ? Il n'aurait jamais dû quitter la local_dict
... Argh ! Nous sommes de retour à l'importation complète httplib
. Peut-être que si on le remplaçait par un objet factice ?
from types import ModuleType
import sys
print len(gc.get_objects()) # 7064 objects in memory
Bloody..... !!
sys.modules['httplib'] = ModuleType('httplib')
print len(gc.get_objects()) # 7066 objects in memory
Modules morts, morts !
import httplib
for attr in dir(httplib):
setattr(httplib, attr, None)
gc.collect()
print len(gc.get_objects()) # 6749 objects in memory
Ok, après toutes les tentatives, le meilleur résultat est +2675 (presque +50%) par rapport au point de départ... Et ça, c'est juste pour un module... Qui n'a même pas quelque chose de gros à l'intérieur...
Ok, maintenant sérieusement, où est mon erreur ? Comment puis-je décharger un module et effacer tout son contenu ? Ou est-ce que les modules de Python sont une fuite de mémoire géante ?
Source complète dans un format plus simple à copier : http://gist.github.com/450606
0 votes
1. Avez-vous déjà examiné, un par un, quels sont exactement les objets restants ? 2. vous essayez de tester en utilisant les modules de "python". Avez-vous essayé la même approche avec un gros module naïf créé par vous ? un module qui ne fait référence à rien d'autre que lui-même ?