2009-05-28 5 views
1

Je travaille sur une bibliothèque qui charge des fichiers (hfd5 - pytables) dans une structure d'objet. Les classes réelles utilisées pour la structure est chargée comme une chaîne à partir du fichier hdf5, puis chargés de cette façon:En python, comment pouvez-vous décharger des classes générées

class NamespaceHolder(dict): 
    # stmt is the source code holding all the class defs 
    def execute(self, stmt): 
     exec stmt in self 

Le problème est, le chargement de plusieurs classes comme celui-ci, fait que les objets apparaissent dans la irrécouvrable une partie de la collection de garbage, à savoir les définitions de classe réelles. Je peux aussi charger ceci dans un dictionnaire global, mais le problème reste des classes orphelines. Est-il possible de décharger les classes?

Le principal problème est la classe. mro attribut, qui contient une référence à la classe elle-même, provoquant des références circulaires que le garbage collector ne peut pas gérer.

Voici un petit boîtier de test pour voir par vous-mêmes:

import gc 

if __name__ == "__main__": 
    gc.enable() 
    gc.set_debug(gc.DEBUG_LEAK) 

    code = """ 
class DummyA(object): 
    pass 
""" 
    context = {} 

    exec code in context 
    exec code in context 

    gc.collect() 
    print len(gc.garbage) 

Juste une remarque: je l'ai déjà fait valoir contre l'utilisation de l'analyse de texte dans un fichier pour créer des classes plus tôt, mais apparemment ils sont mis sur l'utilisation ici et voir des avantages que je n'ai pas, alors s'éloigner de cette solution n'est pas réalisable maintenant.

+0

En fait, s'éloigner de cette non-solution est toujours faisable. S'il encombre la mémoire avec une corbeille irrécupérable, cela ne fonctionne pas. –

+0

Je me souviens avoir lu quelque part (comp.lang.python? La liste Python-Dev? Ne me souviens pas où) que l'équipe de base de développement sait parfaitement que les objets de classe ne peuvent pas être collectés, et IIRC Guido a dit "si vous 'est de créer dynamiquement dans votre code des milliers de classes, il y a quelque chose qui cloche avec votre algorithme', mais ICBW. – tzot

Répondre

1

Le fichier gc.set_debug (gc.DEBUG_LEAK) provoque la fuite. Essayez ceci:

import gc 

def foo():        
    code = """ 
class DummyA(object): 
    pass    
""" 
    context = {} 
    exec code in context 
    exec code in context 

    gc.collect() 
    print len(gc.garbage), len(gc.get_objects()) 

gc.enable() 
foo(); foo() # amount of objects doesn't increase 
gc.set_debug(gc.DEBUG_LEAK) 
foo() # leaks 
+0

Merci beaucoup. J'ai cependant remarqué que toutes mes fuites disparaissaient quand j'ai éteint gc.DEBUG_LEAK – Staale

1

Je pense que le GC peut faire face à des références circulaires, mais vous devez faire est de supprimer la référence des globals() dict:

try: 
    del globals()['DummyA'] 
except KeyError: 
    pass 

sinon il y aura une référence non circulaire à la objet de classe qui va l'arrêter d'être nettoyé.

+0

Jetez un oeil à http://stackoverflow.staale.org/919924.png Ceci est le graphique cyclique qui provient de l'exécution du code ci-dessus. Le tuple référencé ici contient (DummyA, objet), et ne peut pas être enlevé ou modifié, et en tant que tel, la classe DummyA ne peut être collectée. – Staale

Questions connexes