2009-05-28 9 views
1

Ich arbeite an einer Bibliothek, die Dateien (Hfd5 - Pytables) in eine Objektstruktur lädt. Die tatsächlichen Klassen für die Struktur verwendet wird, werden als String aus der hdf5 Datei geladen und dann auf diese Weise geladen:In Python, wie können Sie generierte Klassen entladen

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

Das Problem ist, mehrere Klassen wie diese laden, Objekte verursacht in den uneinbringlichen zu erscheinen Teil der Garbage Collection, nämlich die eigentlichen Klassendefinitionen. Ich kann das auch in ein globales Wörterbuch laden, aber das Problem bleibt von verwaisten Klassen. Gibt es eine Möglichkeit, die Klassen zu entladen?

Das Hauptproblem ist die Klasse. mro Attribut, das einen Verweis auf die Klasse selbst enthält, der zirkuläre Referenzen verursacht, die der Garbage Collector nicht verarbeiten kann.

Hier ist ein kleiner Testfall für mich selbst zu sehen:

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) 

Nur ein Hinweis: Ich habe argumentiert, bereits gegen früher für die Erstellung von Klassen in einer Datei Parsen aus Text verwenden, aber anscheinend sind sie setzen auf mit es hier und sehen einige Vorteile, die ich nicht, so weg von dieser Lösung ist jetzt nicht machbar.

+0

Eigentlich weg von dieser Nicht-Lösung ist immer machbar. Wenn es Speicher mit nicht-sammelbarem Papierkorb überfüllt, funktioniert es nicht. –

+0

Ich erinnere mich irgendwo lesen (comp.lang.python? Die Python-Dev-Liste? Kann mich nicht erinnern, wo), dass das Core-Dev-Team ganz gut die Tatsache, dass Klassenobjekte nicht gesammelt werden können, und IIRC Guido sagte "wenn Sie "In Ihrem Code erstellen Sie dynamisch Tausende von Klassen, da stimmt etwas nicht mit Ihrem Algorithmus", sondern ICBW. – tzot

Antwort

1

Die gc.set_debug (gc.DEBUG_LEAK) verursacht das Leck. Versuchen Sie dies:

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

Vielen Dank. Ich bemerkte jedoch, dass alle meine Lecks verschwanden, als ich gc.DEBUG_LEAK ausschaltete – Staale

1

ich denke, die GC mit zirkulären Referenzen zu bewältigen, aber Sie tun müssen, sind die Referenz von dem Globals entfernen() dict:

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

sonst wird es einen unrunden Bezug auf die seine Klassenobjekt, das aufhört, aufgeräumt zu werden.

+0

Werfen Sie einen Blick auf http://StackOverflow.Staale.org/919924.png Dies ist das zyklische Diagramm, das aus dem Ausführen des obigen Codes stammt. Das Tupel, auf das hier verwiesen wird, enthält (DummyA, Objekt) und kann nicht entfernt oder geändert werden, und daher kann die DummyA-Klasse nicht gesammelt werden. – Staale