每当我调用此函数时,每次调用的内存使用量都会增加很多,所以我认为这里有一些内存泄漏。
PyObject *pScript, *pModule, *pFunc, *pValue;
PyObject *pArgs = NULL;
long ret = 1;
// Initialize python, set system path and load the module
pScript = SetPyObjectString(PYTHON_SCRIPT_NAME);
PyRun_SimpleString("import sys");
PyRun_SimpleString("sys.path.append('"PYTHON_SCRIPT_PATH"')");
pModule = PyImport_Import(pScript);
Py_XDECREF(pScript);
if (pModule != NULL) {
// Get function object from python module
pFunc = PyObject_GetAttrString(pModule, operation.c_str());
if (pFunc && PyCallable_Check(pFunc)) {
// Create argument(s) as Python tuples
if (operation == UPDATE_KEY) {
// If operation is Update key, create two arguments - key and value
pArgs = PyTuple_New(2);
}
else {
pArgs = PyTuple_New(1);
}
pValue = SetPyObjectString(key.c_str());
// Set argument(s) with key/value strings
PyTuple_SetItem(pArgs, 0, pValue);
if (operation == UPDATE_KEY) {
// If operation is Update key, set two arguments - key and value
pValue = SetPyObjectString(value.c_str());
PyTuple_SetItem(pArgs, 1, pValue);
}
// Call the function using function object and arguments
pValue = PyObject_CallObject(pFunc, pArgs);
Py_XDECREF(pArgs);
if (pValue != NULL) {
// Parse the return values
ret = PyLong_AsLong(PyList_GetItem(pValue, 0));
value = GetPyObjectString(PyList_GetItem(pValue, 1));
}
else {
ERROR("Function call to %s failed", operation.c_str());
}
Py_XDECREF(pValue);
Py_XDECREF(pFunc);
}
else {
ERROR("Cannot find function in python module");
}
Py_XDECREF(pModule);
}
else {
ERROR("Failed to load python module");
}
当我的代码中的这个C ++代码段调用python脚本并且我想知道原因时,我正在泄漏一些内存。我想我的Py_DECREFs做错了。任何帮助将不胜感激。
答案 0 :(得分:0)
我从快速的目光中发现了一个失踪的减压:
pFunc = PyObject_GetAttrString(pModule, operation.c_str());
if (pFunc && PyCallable_Check(pFunc)) {
// ...
Py_XDECREF(pFunc);
}
这将泄漏与operation
匹配的任何不可调用属性。
pValue
的两次重新分配...我认为没关系,因为PyTuple_SetItem
窃取了对每个原始值的引用。
对于您询问的这一行:
value = GetPyObjectString(PyList_GetItem(pValue, 1));
PyList_GetItem
返回一个借来的引用,所以你没有减去它的事实是正确的。
但我没有看到value
在任何地方或GetPyObjectString
的声明,所以我不知道那部分是做什么的。也许它只是从PyUnicodeObject *
中获取一个借来的缓冲区并将其复制到某个C ++ wstring
或UTF-32字符串类型中,或者它可能泄漏了Python对象或复制的缓冲区,或者返回了原始C你刚刚在这里泄漏的缓冲区,或者......谁知道?
但我当然不相信互联网上的某些人会在快速扫描中发现所有这些人。学习使用内存调试器。
或者:你正在使用C ++。 RAII几乎是使用C ++的重点 - 换句话说,不是使用原始PyObject *
值,而是可以使用智能指针自动为您量身定制。或者,更好的是,使用像PyCXX这样的现成库。