Py_Finalize() leak?

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.
booth
User
Beiträge: 44
Registriert: Mittwoch 31. Oktober 2007, 21:30
Wohnort: Durham, U.K.

Py_Finalize() leak?

Beitragvon booth » Dienstag 17. Februar 2009, 12:01

Hallo,

ich beschaeftige mich gerade mit dem Einbetten eines Python-Skriptes in eine DLL. Selbige hat folgenden Code (der nicht sehr viel macht, weil ich das meiste zum Debuggen auskommentiert habe):

Code: Alles auswählen

#include "DLLTest.h"
using namespace std;

extern "C"
{
   DECLDIR int getDataPy(CStr LStr, dataAnalogHdl inA, long samplerate) {
   PyObject *pName, *pModule, *pFunc;
   PyObject *pArgs, *pValue;

   char *patternString = "pattern(10,100,1,1,2,3,4,5,6,7,8)\n";

   Py_Initialize();
   _import_array();

   pName = PyString_FromString("pattern");
   pModule = PyImport_Import(pName);
   Py_DECREF(pName);

   if (pModule != NULL) {
      pFunc = PyObject_GetAttrString(pModule, "getData");

      pArgs = PyTuple_New(2);
      PyTuple_SetItem(pArgs, 0, PyString_FromString(patternString));
      PyTuple_SetItem(pArgs, 1, PyInt_FromLong(samplerate));

      if (pFunc && PyCallable_Check(pFunc)) {
         pValue = PyObject_CallObject(pFunc, pArgs);
         Py_XDECREF(pArgs);
         Py_XDECREF(pFunc);
         Py_XDECREF(pModule);

      }
      else {
                        Py_XDECREF(pArgs);
         Py_XDECREF(pFunc);
         Py_XDECREF(pModule);
         return 2;
      }
   }
   else {
      return 1;
   }
   Py_Finalize();
   return 0;
}



Die betreffende Python-Funktion sieht so aus:

Code: Alles auswählen

def getData(inS, samplerate):
 
    f = open("error.log", 'a')
    f.write(str(inS))
    f.close()
   
    return 0


Die erzeugte DLL wird aus LabView aufgerufen. Einen Aufruf ueberlebt Labview auch, beim zweiten stuerzt es dann ab. Das ist anders, wenn ich das Py_Finalize() auskommentiere. Meine Frage ist jetzt wie ich das Leck finde (und es dann ggf. auch melden kann). In der Doku zu Py_Finalize() wird darum gebeten, dass man sowas meldet, nur weiss ich nicht wie ich den Fehler quantifiziere.

vG, U.
CM
User
Beiträge: 2464
Registriert: Sonntag 29. August 2004, 19:47
Kontaktdaten:

Beitragvon CM » Dienstag 17. Februar 2009, 12:50

Hm, mal ein Schuss ins Blaue: Was, wenn Du die Initialisierung und die Finalisierung in jeweils eigene Funktionen auslagerst? Du könntest zum Initialisieren checken, ob Du noch Initialisieren mußt (nur beim ersten Aufruf) und Finalisieren, nur, wenn Du den Interpreter neustarten oder die Applikation schließen willst. Auf diese Weise würdest Du auch viel Overhead los.

Keine Ahnung, ob es helfen wird.

Gruß,
Christian
booth
User
Beiträge: 44
Registriert: Mittwoch 31. Oktober 2007, 21:30
Wohnort: Durham, U.K.

Beitragvon booth » Dienstag 17. Februar 2009, 13:30

CM hat geschrieben:... und Finalisieren, nur, wenn Du den Interpreter neustarten oder die Applikation schließen willst. Auf diese Weise würdest Du auch viel Overhead los.


Ich rufe Py_Finalize ja am Ende der Funktion auf, das "Programm" ist damit beendet. Es gibt keine Schleifenaufrufe dieser Funktion.

Was fuer ein Overhead?

Ich werde Py_Initialize() mal in eine eine if-Abfrage packen. Mal sehen ob sich was aendert.

Ich habe halt immer sorge, dann wenn ich Py_Finalize() nicht aufrufe, ich den Speicher zumuelle. Ich bin mir ueber die einzelnen Funktionen sowieso noch nicht so im Klaren (Py_DECREF und Py_XDECREF sind fuer mich boemische Doerfer).

vG, U.
Benutzeravatar
Trundle
User
Beiträge: 591
Registriert: Dienstag 3. Juli 2007, 16:45

Beitragvon Trundle » Dienstag 17. Februar 2009, 19:04

Sieht irgendwie nach einem Bug in numpy aus. Nach `Py_Finalize()` führt ein erneuter Import von "numpy.core.multiarray" zum Segfault. Der folgende Code reicht aus:

Code: Alles auswählen

#include "Python.h"
#include "numpy/arrayobject.h"

int main(int argc, char *argv[])
{
    int i;
    for (i=0; i != 3; ++i)
    {
        Py_Initialize();
        Py_XDECREF(PyImport_ImportModule("numpy.core.multiarray"));
        Py_Finalize();
    }
    return 0;
}
"Der Dumme erwartet viel. Der Denkende sagt wenig." ("Herr Keuner" -- Bertolt Brecht)
booth
User
Beiträge: 44
Registriert: Mittwoch 31. Oktober 2007, 21:30
Wohnort: Durham, U.K.

Beitragvon booth » Dienstag 17. Februar 2009, 19:24

Eigentlich gibt es bei mir aber nur einmal Py_Finalize(), also keine Schleife wie in Deinem Beispiel. D.h. ich bin mir nicht ganz sicher, wie und was LabView mit der DLL macht, das zeigt manchmal ein sehr seltsamens Verhalten.

Aber eigentlich wuerde ich denken, wenn die DLL einmal durchgelaufen ist und ich es dann nochmals starte und vorher alles aus dem Speicher entfernt ist (Py_Finalize()), dann sollte der naechste Durchlauf doch vom Scratch wieder anfangen, nicht?

vG, U.
Benutzeravatar
Trundle
User
Beiträge: 591
Registriert: Dienstag 3. Juli 2007, 16:45

Beitragvon Trundle » Dienstag 17. Februar 2009, 19:46

Die Schleife dient ja lediglich dazu, die zwei Aufrufe zu simulieren. Oder wird die DLL jedes Mal wieder neu geladen (kenn mich mit LabView nicht aus)?
"Der Dumme erwartet viel. Der Denkende sagt wenig." ("Herr Keuner" -- Bertolt Brecht)
Benutzeravatar
HerrHagen
User
Beiträge: 430
Registriert: Freitag 6. Juni 2008, 19:07

Beitragvon HerrHagen » Dienstag 17. Februar 2009, 21:26

booth
User
Beiträge: 44
Registriert: Mittwoch 31. Oktober 2007, 21:30
Wohnort: Durham, U.K.

Beitragvon booth » Dienstag 17. Februar 2009, 21:26

Ich habe bisher nicht rausfinden koennen ob die DLL neugeladen wird oder im Speicher verbleibt. Allerdings kann man auf die DLL nicht zugreifen solange LabView aktiv ist. Das deutet wohl eher darauf hin, dass LabView sie haelt. Ich dachte immer DLLs werden nach Prozessende entlassen und ggf neu geladen.
booth
User
Beiträge: 44
Registriert: Mittwoch 31. Oktober 2007, 21:30
Wohnort: Durham, U.K.

Beitragvon booth » Dienstag 17. Februar 2009, 22:10

HerrHagen hat geschrieben:Ohne genau zu wissen ob's das ist:
http://www.nabble.com/Embedding-numpy-works-once,-but-not-twice---td21772015.html


Jup, dass scheint mir das gleiche Problem zu sein, allerdings schreiben die

Gabriel Genellina-7 hat geschrieben:The problem is not with NumPy. You can't run Py_Initialize/Py_Finalize
more than once. Python doesn't have any mechanism to un-initialize loaded
modules, and any static data that NumPy had initialized the first time it
is imported becomes invalid the second time.
Call Py_Initialize at the start of your program, and Py_Finalize at the
end, never more than once.


Ich kann versuchen in der DLL eine Funktion zu schreiben, die ganz zu Beginn beim Starten des LabView-Programms Python startet und beim Beenden wieder schliesst. Keine Ahnung ob das funktioniert. Morgen mal probieren...

vG, U.

Wer ist online?

Mitglieder in diesem Forum: Dembrix, Tim_12