问题描述
我正在编写嵌入 Python 模块的 C++ 代码。我在开始时只导入了一次模块;然后,C++ 代码从中重复调用单个函数。为此,我使用了以下语法(这里报告了一个最小的工作示例,假设 Python 函数采用两个浮点参数并返回一个浮点值):
int main() {
// Initialise the Python interpreter
Py_Initialize();
PyObject *pFunc = NULL,*pModule = NULL;
const char* module_name = "mod_name";
const char* function_name = "fun_name";
// Importing module
pModule = PyImport_ImportModule(module_name);
// Sanity check on module pointer
if (pModule == NULL) {
PyErr_Print();
std::cout << "ERROR importing module" << std::endl;
std::exit(1);
}
// Import function from Python module
pFunc = PyObject_GetAttrString(pModule,function_name);
if (pFunc == NULL) {
Py_CLEAR(pModule);
PyErr_Print();
std::cout << "ERROR getting test function" << std::endl;
std::exit(1);
}
// Free module pointer
Py_CLEAR(pModule);
double val1 = 1.5;
double val2 = 2.5;
for (int i = 0; i < 10; i++){
// Specify inputs of the Python function that has to be called
pArgs = PyTuple_Pack(2,PyFloat_FromDouble(val1),PyFloat_FromDouble(val2) );
// Checking that the tuple packing was performed correctly
if (pArgs == NULL) {
PyErr_Print();
std::cout << "ERROR packing arguments" << std::endl;
std::exit(1);
}
// Call the Python function and store the returned value in pValue
pValue = PyObject_CallObject(pFunc,pArgs);
// Checking that the function call was performed correctly
if (pValue == NULL) {
Py_CLEAR(pArgs);
PyErr_Print();
std::cout << "ERROR getting value from function" << std::endl;
std::exit(1);
}
//SUCCESSFULLY COMPLETED PYTHON CALL
double res= PyFloat_AsDouble(pValue);
// Free all the allocated memory
Py_CLEAR(pArgs);
Py_CLEAR(pValue);
}
// Free the shared pointer to python function
Py_CLEAR(pFunc);
Py_Finalize();
return 0;
}
我已经使用 valgrind 分析了我的 C++ 可执行文件,以检查内存泄漏。虽然当我隔离代码的 C++ 部分时一切正常,但只要我运行带有嵌入式 Python 部分的完整代码,就会出现内存泄漏。请参阅以下原始代码的损失报告示例:valgrind loss report
我知道 valgrind 在与 Python 代码交互时可能会给出奇怪的结果,所以我在这里联系以查看在将 Python 嵌入到 C++ 中时是否有检查内存泄漏的最佳实践。
另外,这是我在这里的第一个问题,所以如果缺少任何有用的信息,请不要犹豫,提出要求!提前致谢
解决方法
您遇到的问题是 valgrind 了解通过 malloc 完成的分配,但它不了解来自 python 领域的分配。因此,如果 malloc 的分配仅从 python 分配中引用,则 valgrind 不会注意到这一点,并且会认为 malloc 的分配已泄露。
我的建议是您使用 https://github.com/vmware/chap,因为它可以识别两种类型的分配。
在没有 valgrind 的情况下运行您的程序,但在您的程序完成之前的某个时刻收集实时核心,使用 gcore 或通过在断点处从 gdb 运行“生成”。
然后启动 chap 并在 chap 提示下尝试以下操作:
count leaked
如果显示非零值,请查看 https://github.com/vmware/chap/blob/master/USERGUIDE.md 以获取有关如何分析泄漏的进一步建议。