下面的函数使用一个python文件句柄,从文件中读取打包的二进制数据,创建一个Python字典并将其返回。如果我不断循环,它将不断消耗RAM。我的RefCounting有什么问题?
static PyObject* __binParse_getDBHeader(PyObject *self, PyObject *args){
PyObject *o; //generic object
PyObject* pyDB = NULL; //this has to be a py file object
if (!PyArg_ParseTuple(args, "O", &pyDB)){
return NULL;
} else {
Py_INCREF(pyDB);
if (!PyFile_Check(pyDB)){
Py_DECREF(pyDB);
PyErr_SetString(PyExc_IOError, "argument 1 must be open file handle");
return NULL;
}
}
FILE *fhDB = PyFile_AsFile(pyDB);
long offset = 0;
DB_HEADER *pdbHeader = malloc(sizeof(DB_HEADER));
fseek(fhDB,offset,SEEK_SET); //at the beginning
fread(pdbHeader, 1, sizeof(DB_HEADER), fhDB );
if (ferror(fhDB)){
fclose(fhDB);
Py_DECREF(pyDB);
PyErr_SetString(PyExc_IOError, "failed reading database header");
return NULL;
}
Py_DECREF(pyDB);
PyObject *pyDBHeader = PyDict_New();
Py_INCREF(pyDBHeader);
o=PyInt_FromLong(pdbHeader->version_number);
PyDict_SetItemString(pyDBHeader, "version", o);
Py_DECREF(o);
PyObject *pyTimeList = PyList_New(0);
Py_INCREF(pyTimeList);
int i;
for (i=0; i<NUM_DRAWERS; i++){
//epochs
o=PyInt_FromLong(pdbHeader->last_good_test[i]);
PyList_Append(pyTimeList, o);
Py_DECREF(o);
}
PyDict_SetItemString(pyDBHeader, "lastTest", pyTimeList);
Py_DECREF(pyTimeList);
o=PyInt_FromLong(pdbHeader->temp);
PyDict_SetItemString(pyDBHeader, "temp", o);
Py_DECREF(o);
free(pdbHeader);
return (pyDBHeader);
}
谢谢参观,
LarsenMTL
最佳答案
PyDict_New()
返回新的引用,请检查docs中的PyDict
。因此,如果您在创建引用计数后立即增加它,则有两个引用。当您将其作为结果值返回时,一个转移到调用方,但另一个永不消失。
您也不需要引用pyTimeList
。创建时是您的。但是,您需要对它进行解密,但是您只需对其解密一次,因此它也被泄漏了。
您也不需要在Py_INCREF
上调用pyDB
。这是一个借用的引用,只要您的函数不返回,它就不会消失,因为它仍然在较低的堆栈框架中引用。
仅当您要将引用保留在其他结构中的某个位置时,才需要增加引用计数。
cf. API docs
关于python - 为什么我的Python C Extension泄漏内存?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/350647/