Seite 1 von 1

Py_Finalize() leak?

Verfasst: Dienstag 17. Februar 2009, 12:01
von booth
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.

Verfasst: Dienstag 17. Februar 2009, 12:50
von CM
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

Verfasst: Dienstag 17. Februar 2009, 13:30
von booth
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.

Verfasst: Dienstag 17. Februar 2009, 19:04
von Trundle
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;
}

Verfasst: Dienstag 17. Februar 2009, 19:24
von booth
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.

Verfasst: Dienstag 17. Februar 2009, 19:46
von Trundle
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)?

Verfasst: Dienstag 17. Februar 2009, 21:26
von HerrHagen

Verfasst: Dienstag 17. Februar 2009, 21:26
von booth
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.

Verfasst: Dienstag 17. Februar 2009, 22:10
von booth
HerrHagen hat geschrieben:Ohne genau zu wissen ob's das ist:
http://www.nabble.com/Embedding-numpy-w ... 72015.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.