Objekt wird nicht vom GarbageCollector eingesammelt

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
cmFBDD
User
Beiträge: 10
Registriert: Mittwoch 21. April 2010, 12:04

Hey Jungs und Mädels,

ich bin totaler Anfänger in Sachen Python und habe ein Problem mit dem GarbageCollector. Um bestimmte Moleküle zu erstellen, benutze ich Pybel. Um dann zu checken, ob diese Moleküle ein bestimmtes Molekulargewicht überschreiten, habe ich eine kleine Funktion gebastelt, die ein Objekt (OBMol) aus einem String erzeugt, aus dem dann das Molekulargewicht genau errechnet werden kann.

Code: Alles auswählen

def getMolWtBool(combined_smile):
    mol = pybel.readstring("smi", combined_smile)
    return not (mol.molwt > 502.01588)

Wenn ich nun meinen Boolean habe, würde ich normalerweise davon ausgehen, dass Python das Objekt mol verwirft und den Speicher freimacht. Leider ist das nicht der Fall, denn mit größeren Inputdatenmengen steigt der Arbeitsspeicherverbrauch enorm. Andere Fehlerquellen konnte ich bisher ausschließen, denn wenn ich das "aufräumen" erzwinge, scheint er das Objekt zu beseitigen. Diese Variante scheint mir aber die schlechteste.

Code: Alles auswählen

gc.set_debug(gc.DEBUG_LEAK)
gc.collect()

Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

cmFBDD hat geschrieben: Wenn ich nun meinen Boolean habe, würde ich normalerweise davon ausgehen, dass Python das Objekt mol verwirft und den Speicher freimacht. Leider ist das nicht der Fall, denn mit größeren Inputdatenmengen steigt der Arbeitsspeicherverbrauch enorm.
Selbst wenn Python das Objekt nicht löschen würde, würde es bei jedem Funktionsaufruf doch überschrieben. Insofern kann es doch gar nicht an dieser Stelle einen Fehler geben - außer die Factoryfunktion beinhaltet das Leck...

Prinzipiell sollte das Objekt aber zum Löschen freigegeben werden, sobald die Funktion abgearbeitet ist. Das wäre zumindest mein Verständnis.
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Die Funktion hat kein Leak. pybel.readstring könnte allerdings eins haben.
cmFBDD
User
Beiträge: 10
Registriert: Mittwoch 21. April 2010, 12:04

Erstmal Danke!

Das bedeutet, wenn der Fehler dort liegt, kann ich wenig ausrichten mit meinen Laienhaften Kenntnissen... ???
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

cmFBDD hat geschrieben:Erstmal Danke!

Das bedeutet, wenn der Fehler dort liegt, kann ich wenig ausrichten mit meinen Laienhaften Kenntnissen... ???
Naja, Du könntest Dir die Funktion mal angucken, nach einer neueren Version gucken, prüfen, ob so ein Bug schon gemeldet wurde und ggf. die Entwickler kontaktieren.

Zudem hast Du uns ja nur einen kleinen Teil gezeigt. Evtl. ist das Problem ja auch ganz woanders bei Dir.

Du könntest auch mal ein minmales Beispiel hier posten, damit wir das ggf. nachvollziehen können :-)
cmFBDD
User
Beiträge: 10
Registriert: Mittwoch 21. April 2010, 12:04

Also ich habe nochmal etwas rumgesucht und es gibt da leider wirklich ein
Problem mit Pybel (oder eher mit Openbabel).

"Memory leak in OBConversion_ReadString - ID: 2978796" sogar ganz aktuell!

http://sourceforge.net/tracker/?func=de ... tid=428740

Ich komme leider nicht um diese Funktion Readstring drum herum! Und daher habe ich mir nun 2 Möglichkeiten überlegt:

1. Ich brauch das Mol-Objekt genau 2 mal an verschiendenen Stellen und muss es auch aus einem String erzeugen! Ich könnte diese beiden Funktionen einfach in 2 Scripte extra schreiben und dann per subprocess aufrufen und die Ergebnisse über die Pipeline abfangen... Dauert aber glaub ich zu lange bei großen Datenmengen...

2. Ich weiß nicht ob sowas machbar ist: Vielleicht könnte ich ein Objekt, indem fall das Mol-Objekt, aus dem Arbeitsspeicher in einen File schreiben...

Habt ihr da Vorschläge????
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

Dein erster Vorschlag wäre ein gangbarer Workaround, wenn auch hässlich. Evtl. wäre auch das Modul [mod]multiprocessing[/mod] was für Dich, dann könntest Du den "Leseprozess" mehrmals benutzen und ihn beenden, wenn der Footprint zu groß wird und so den Speicher wieder frei geben.

Dein zweiter Vorschlag funktioniert nur, wenn Du zwischendurch den lesenden Python-Prozess beendest, was wohl noch unpraktikabler sein dürfte.

Besser wäre es natürlich, das Speicherleck zu fixen. Ich hab mir den Quellcode mal angeschaut (allerdings nur überflogen), tatsächlich wird in der beschiebenen Methode Speicher reserviert und ein Pointer hierauf zurückgegeben. Ein bool-Flag soll die spätere nötige Freigabe anzeigen. Hier müßte man auf Callerebene mal schauen, ob das auch für alle Fälle beachtet wird.
Komisch ist die zurückgebene Methode Read. Ist die gzip-Prüfung erfolgreich, so wird `pInStream` dereferenziert einem zip_istream übergeben und anschliessend an `pInStream` gebunden. Das sieht nach einem möglichen Speicherleck aus.
cmFBDD
User
Beiträge: 10
Registriert: Mittwoch 21. April 2010, 12:04

Also ich habe mal rumprobiert mit der Variante Multiprocess, aber so richtig gefallen tut mir das nicht! Verzögert den ohnehin schon sehr langsamen Prozess nur noch.

Meinst du es ist so schwer den Fehler zu fixxen? Ich habe leider glaub ich wirklich zu wenig Know-how um da ranzugehen.
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

Ohne genauere Kenntnis des Codes und dessen Funktionsweise ist es schwierig, so etwas zu fixen. Da fährst Du mit einem ausführlichen Bugreport besser.
Ich habe mich trotzdem mal hingesetzt und das Beispiel auf der Bugreportseite zurückverfolgt und gleich 2 Speicherlecks gefunden:

Code: Alles auswählen

diff -upr openbabel-2.2.3/src/formats/smilesformat.cpp patched/src/formats/smilesformat.cpp
--- openbabel-2.2.3/src/formats/smilesformat.cpp	2009-07-31 19:28:36.000000000 +0200
+++ patched/src/formats/smilesformat.cpp	2010-04-23 22:57:25.000000000 +0200
@@ -820,7 +820,12 @@ namespace OpenBabel {
   public:
 
     OBSmilesParser() { }
-    ~OBSmilesParser() { }
+    ~OBSmilesParser() {
+        map<OBAtom*,TetrahedralStereo*>::iterator iter;
+        for(iter=_tetrahedralMap.begin(); iter!=_tetrahedralMap.end(); ++iter) {
+            delete iter->second;
+        }
+     }
 
     bool SmiToMol(OBMol&,const string&);
     bool ParseSmiles(OBMol&);
diff -upr openbabel-2.2.3/src/obconversion.cpp patched/src/obconversion.cpp
--- openbabel-2.2.3/src/obconversion.cpp	2009-06-26 19:41:05.000000000 +0200
+++ patched/src/obconversion.cpp	2010-04-23 22:34:37.000000000 +0200
@@ -271,6 +271,7 @@ namespace OpenBabel {
       pOutStream=NULL;
       NeedToFreeOutStream = false;
     }
+    delete pLineEndBuf;
   }
   //////////////////////////////////////////////////////
 
Das erste Leck ist tief im smile-Parser vergraben. Hier wird im Falle eines '@' im smile-String eine STL map<> mit Pointern erstellt. Der Speicher wird allerdings von C++ nicht automatisch freigegeben, daher die explizite Version. Ich bin mir in keinster Weise darüber im Klaren, wo die Freigabe genau zu erfolgen hat, dafür fehlt mir der Überblick über die Funktionsweise des Parsers und des OBMol-Konstruktes. Hier muß in jedem Falle ein Entwickler drüber schauen.
Das zweite Leck scheint ein vergessener Pufferpointer von pInputStream in OBConversion zu sein, den hab ich mal dem Destructor hinzugefügt. Auch hier wiederum keine Garantie bzgl. Nebeneffekten.

Mit den obigen Änderungen läuft das Bsp. ohne Speicherleck durch (funktioniert auch mit dem Python-binding).

Allerdings glaube ich, dass in openbabel noch mehr Lecks versteckt sind (zb. die gzip-Sache war mir noch aufgefallen, habs aber nicht getestet). Insgesamt wirkt in den Quelldateien der Umgang mit 'new' etwas abenteuerlich. ;)

Vllt. hilft Dir das ja weiter und Du kannst hieraus einen vernünftigen Bugreport erstellen.

Grüsse jerch

Edit:
Falschen Patch eingestellt :oops:
cmFBDD
User
Beiträge: 10
Registriert: Mittwoch 21. April 2010, 12:04

WOW Danke!!!

Also ich habe mir das ganze angesehen und verstehe was du gemacht hast. Für meine Bedürfnisse wird dieser HotFix glaub ich vollkommen reichen!

Jetzt muss ich nur noch das ganze auch unter Windows umgesetzt bekommen... weil Openbabel habe ich einfach mit dem WindowsInstaller installiert!

Aber nochmals Danke! Das ganze Brauch ich nämlich für meine Bachelorarbeit und jetzt nochmal alles mit anderen Mitteln umsetzen, hätte einfach zu viel Zeit gekostet!
cmFBDD
User
Beiträge: 10
Registriert: Mittwoch 21. April 2010, 12:04

Hey Jerch,

nochmals vielen Dank für deine Bemühungen. Sag mal, du konntest ja die Änderungen am Source sogar ausprobieren... Hast du das ganze unter Linux gebaut? Hast du nach der Anleitung im Wiki gearbeitet? Ich bekomm es unter Windows gar nicht erst deployed Sad

Gruß der Chris
Zuletzt geändert von cmFBDD am Freitag 30. April 2010, 16:56, insgesamt 1-mal geändert.
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

Ja ich nutze hier Opensuse, mit dem Dreisatz hatte ich es lokal installiert und konnte die Lecks mit einer Mischung aus Valgrind und printf-Debugging relativ schnell ausfindig machen. Von einer Anleitung in einem Wiki weiss ich nichts. Übrigens ist das Speicherleck im Parser in der SVN-Version behoben, dafür gibts neue zu entdecken ;)

Wo klemmts denn bei Dir? Wenn ich mich recht entsinne, lagen den Quelldateien Projektmappen für VS2005 und 2008 bei, vllt. gibt es da aber ein paar Dinge bzgl. des Compilers zu beachten. Läuft denn wenigstens der Build der Bibliothek durch? Dann könntest Du das ja in C++ umsetzen. Für das Python-Binding brauchst Du dann noch SWIG und die Python-includes, hier mußt Du ggf. darauf achten, dass die Libs kompatibel zueinander sind (im Zweifelsfalle denselben Compiler benutzen).

Poste doch mal den Anfang der Fehlermeldung.

Grüsse jerch
cmFBDD
User
Beiträge: 10
Registriert: Mittwoch 21. April 2010, 12:04

Na das Bauen mit Visual 2008 ergab keine Errors. Mit der Anleitung für 2005 gabs nur Probleme! Habe sogar die GUI mit WXwidget compiled...

Ich habe jetzt mal nen Installer gebaut mit dem NISI-Tool... bis auf ein Warning gab es da auch keine Probleme... Wenn ich jetzt den Installer benutze hat er beim import von Pybel in Python einen Fehler im swig_import_helper.... _mod referenced before assignment.... glaube aber nicht, dass das am Script liegt sondern eher, dass ich nochmal die Pythonbindings bauen muss! dazu gibt es aber keinerlei Dokumentation und die ausm Wiki kann ich nicht umsetzen da im Trunk die Daten so nicht mehr vorhanden sind...

und sowas nennt man dann Bioinformatiker ;-P
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

Welche Version hast Du denn jetzt gebaut? SVN trunk?

Mit dieser habe ich das Python-Binding nicht gebaut, nur mit der 2.2.3. Das Makefile ist dort nur für die Lib zuständig, das Python-Binding liess sich aber problemlos mit 'python setup.py build' aus dem Python-Ordner heraus bauen. Keine Ahnung, inwieweit das im trunk umgestellt wurde und Du hier irgendeinen cmake-Schalter benutzen musst oder ob der 'setup.py build'-Weg noch funktioniert. Der Fehler deutet zumindest darauf hin, dass etwas mit dem C++-Teil des SWIG-Modules nicht stimmt. Ist das denn mit kompiliert worden? (Du musst es auf jeden Fall irgendwo erstellen, sonst fehlt es ja gänzlich.) Stimmen die Pfade?
Mehr als vage Vermutungen und Fragen habe ich hier im Moment auch nicht.

Meld Dich nochmal, falls Du da nicht weiterkommst, ich würde dann bei Gelegenheit nochmal draufschauen, 4 Augen sehen bekanntlich mehr als 2...

Grüsse jerch
cmFBDD
User
Beiträge: 10
Registriert: Mittwoch 21. April 2010, 12:04

Ich habe mich erst mal nicht weiter damit beschäftigt! Stattdessen habe ich mal das Multiprozessing ausprobiert und das ist ja recht easy! Allerdings für sehr große Simulationen mit meinem Programm, denk ich doch nicht geeignet, dass es die Laufzeit doch stark beeinflußt!

Also werde ich mir heut nachmittag nochmal ansehen was genau beim bauen von Openbabel 2.3.0 noch fehlt!

Die Variante mit der Installation der Bindings funktionierte auch nicht! Da fehlte ihm irgendwas... muss ich mir heute nachmittag aber nochmal ansehen, da ich es nur aufm Heimrechner habe....
cmFBDD
User
Beiträge: 10
Registriert: Mittwoch 21. April 2010, 12:04

Hey also... ich habe es mal versucht wie, also die bindings über "python setup.py install" zu installieren! Da fehlt ihm die openbabel-python.cpp! Die glaub ich erhalt ich wenn ich die windowsOBF speziel OBPythonOBF baue! Dabei fehlt ihm aber die BabelConfig.h! Diese ist zwar auch im Buildordner vorhanden aber die findet er trotzdem nicht!

Weiß echt nicht wie ich das machen soll...
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

So gehts mit VS2005 und openbabel 2.2.3:
  • openbabel Projektmappe mit VS öffnen (unter openbabel-2.2.3\windows-vc2005)
  • benötigte include/lib/bin-Pfade setzen, das sind im einzelnen (hab hoffentlich keinen vergessen):
    • include: Pfad zu zlib.h
    • include: Pfad zu Python.h (wird mit dem Windows-binary mitgeliefert)
    • lib: Pfad zu pythonXX.lib
    • bin: Pfad zum SWIG binary
  • Rechtsklick auf OBPythonOBF --> Erstellen
  • Warten (Kaffeetrinken)
Im Ordner openbabel-2.2.3\windows-vc2005\OBPythonOBF\dist findest Du dann das fertige Pythonpaket als Installer.
Dem Paket fehlen allerdings die DLLs. Die könntest Du entweder mit einem selbstgestrickten Installer (z.B. fürs "große" Openbabel) mitliefern oder an das setup.py-Skript anhängen (quasi als standalone-Pythonversion).

Das zu-Fuss-Bauen an der Konsole geht unter Windows natürlich auch, würde ich Dir aber nicht empfehlen, da das zur unnötigen Pfadjongliererei wird und es mit VS so schön vorkonfiguriert ist.
cmFBDD
User
Beiträge: 10
Registriert: Mittwoch 21. April 2010, 12:04

also ich habe nochmal das ganze mit VC 2008 gebaut... und auch den Installer gebaut... wieder das selbe! Die Vorgängerversion OB-2.3.0s1 (vom 02.04.2010) ausm Netz macht genau die selben Probleme, also _mod referenced before...

wenn ich jetzt beispielsweise "import _openbabel" in Python benutze sagt er mir DLL load failed!

Welche DLL-Dateien aus dem Build brauch ich denn und wo müssen die hin?
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

Ich hab im Moment keine Zeit, das nochmal mit der SVN-Version zu testen. Vllt. gegen Ende der Woche...
cmFBDD hat geschrieben:Welche DLL-Dateien aus dem Build brauch ich denn und wo müssen die hin?
Ein kurzer Blick in die Projektdatei zeigt folgende Abhängigkeiten:

Code: Alles auswählen

../OBDLL.lib;../OBConv.lib;../OBDESC.lib;../oberror.lib;../obcommon.lib
Wo die DLLs liegen müssen, damit Windows sie finden kann, steht hier.
Antworten