L'exemple minimal suivant d'appel d'une fonction Python à partir de C++ présente une fuite de mémoire sur mon système :
script.py
:
import tensorflow
def foo(param):
return "something"
main.cpp
:
#include "python3.5/Python.h"
#include <iostream>
#include <string>
int main()
{
Py_Initialize();
PyRun_SimpleString("import sys");
PyRun_SimpleString("if not hasattr(sys,'argv'): sys.argv = ['']");
PyRun_SimpleString("sys.path.append('./')");
PyObject* moduleName = PyUnicode_FromString("script");
PyObject* pModule = PyImport_Import(moduleName);
PyObject* fooFunc = PyObject_GetAttrString(pModule, "foo");
PyObject* param = PyUnicode_FromString("dummy");
PyObject* args = PyTuple_Pack(1, param);
PyObject* result = PyObject_CallObject(fooFunc, args);
Py_CLEAR(result);
Py_CLEAR(args);
Py_CLEAR(param);
Py_CLEAR(fooFunc);
Py_CLEAR(pModule);
Py_CLEAR(moduleName);
Py_Finalize();
}
compilé avec
g++ -std=c++11 main.cpp $(python3-config --cflags) $(python3-config --ldflags) -o main
et l'exécuter avec valgrind
valgrind --leak-check=yes ./main
produit le résumé suivant
LEAK SUMMARY:
==24155== definitely lost: 161,840 bytes in 103 blocks
==24155== indirectly lost: 33 bytes in 2 blocks
==24155== possibly lost: 184,791 bytes in 132 blocks
==24155== still reachable: 14,067,324 bytes in 130,118 blocks
==24155== of which reachable via heuristic:
==24155== stdstring : 2,273,096 bytes in 43,865 blocks
==24155== suppressed: 0 bytes in 0 blocks
J'utilise Linux Mint 18.2 Sonya
, g++ 5.4.0
, Python 3.5.2
y TensorFlow 1.4.1
.
Suppression import tensorflow
fait disparaître la fuite. S'agit-il d'un bug dans TensorFlow ou ai-je fait quelque chose de mal ? (Je m'attends à ce que la dernière hypothèse soit la bonne).
De plus, lorsque je crée une couche Keras en Python
#script.py
from keras.layers import Input
def foo(param):
a = Input(shape=(32,))
return "str"
et exécuter l'appel à Python à partir de C++ de manière répétée
//main.cpp
#include "python3.5/Python.h"
#include <iostream>
#include <string>
int main()
{
Py_Initialize();
PyRun_SimpleString("import sys");
PyRun_SimpleString("if not hasattr(sys,'argv'): sys.argv = ['']");
PyRun_SimpleString("sys.path.append('./')");
PyObject* moduleName = PyUnicode_FromString("script");
PyObject* pModule = PyImport_Import(moduleName);
for (int i = 0; i < 10000000; ++i)
{
std::cout << i << std::endl;
PyObject* fooFunc = PyObject_GetAttrString(pModule, "foo");
PyObject* param = PyUnicode_FromString("dummy");
PyObject* args = PyTuple_Pack(1, param);
PyObject* result = PyObject_CallObject(fooFunc, args);
Py_CLEAR(result);
Py_CLEAR(args);
Py_CLEAR(param);
Py_CLEAR(fooFunc);
}
Py_CLEAR(pModule);
Py_CLEAR(moduleName);
Py_Finalize();
}
la consommation de mémoire de l'application augmente continuellement à l'infini pendant l'exécution.
Je suppose donc qu'il y a quelque chose de fondamentalement erroné dans la façon dont j'appelle la fonction python à partir de C++, mais qu'est-ce que c'est ?