我正在尝试追踪Python C扩展中的内存泄漏,并且无法理解为什么我的代码会提供引用计数。
参考下面的代码示例,我想了解以下内容,
这是一个简短的代码示例。 (我在Windows 10上使用64位Python 2.7,使用VS2012。)
// test.c : Test python reference counting
//
#include <stdlib.h>
#include <Python.h>
int main()
{
PyObject *PythonFunctionInput;
FILE *fid;
PyObject *tempPyObj;
PyObject *tempPyObjInt;
const int x = 1; // This is to mimic data in my actual application
const int y = 1;
const int z = 1;
Py_InitializeEx(0);
PythonFunctionInput = PyDict_New();
fid = fopen("TestOutputFile.txt", "wt");
fprintf(fid,"%d\n",(int)Py_REFCNT(PythonFunctionInput)); // 1
// Block 1
tempPyObj = PyString_FromString("name1");
fprintf(fid,"%d ",(int)Py_REFCNT(tempPyObj)); // 1
PyDict_SetItemString(PythonFunctionInput,"fieldname1",tempPyObj);
fprintf(fid,"%d ",(int)Py_REFCNT(tempPyObj)); // 2
Py_DECREF(tempPyObj);
fprintf(fid,"%d\n",(int)Py_REFCNT(tempPyObj)); // 1
// Block 2
tempPyObjInt = PyInt_FromLong((long)x);
fprintf(fid,"%d ",(int)Py_REFCNT(tempPyObjInt)); // 118 why?
PyDict_SetItemString(PythonFunctionInput,"fieldname2",tempPyObjInt);
fprintf(fid,"%d ",(int)Py_REFCNT(tempPyObjInt)); // 119
Py_DECREF(tempPyObjInt);
fprintf(fid,"%d\n",(int)Py_REFCNT(tempPyObjInt)); //118
// Block 3
tempPyObjInt = PyInt_FromLong((long)y);
fprintf(fid,"%d ",(int)Py_REFCNT(tempPyObjInt)); // 119
PyDict_SetItemString(PythonFunctionInput,"fieldname3",tempPyObjInt);
fprintf(fid,"%d ",(int)Py_REFCNT(tempPyObjInt)); // 120
Py_DECREF(tempPyObjInt);
fprintf(fid,"%d\n",(int)Py_REFCNT(tempPyObjInt)); // 119
// Block 4
tempPyObj = PyInt_FromLong((long)z);
fprintf(fid,"%d ",(int)Py_REFCNT(tempPyObj)); // 120 why?
PyDict_SetItemString(PythonFunctionInput,"fieldname4",tempPyObj);
fprintf(fid,"%d ",(int)Py_REFCNT(tempPyObj)); // 121
Py_DECREF(tempPyObj);
fprintf(fid,"%d\n",(int)Py_REFCNT(tempPyObj)); // 120
// Block 5
tempPyObj = PyString_FromString("name5");
fprintf(fid,"%d ",(int)Py_REFCNT(tempPyObj)); // 1 why?
PyDict_SetItemString(PythonFunctionInput,"fieldname5",tempPyObj);
fprintf(fid,"%d ",(int)Py_REFCNT(tempPyObj)); // 2
Py_DECREF(tempPyObj);
fprintf(fid,"%d\n",(int)Py_REFCNT(tempPyObj)); // 1
// Block 6
Py_DECREF(PythonFunctionInput);
fprintf(fid,"%d\n",(int)Py_REFCNT(PythonFunctionInput)); // 0
fprintf(fid,"%d ",(int)Py_REFCNT(tempPyObj)); // why not 0 ?
Py_Finalize();
fclose(fid);
return 0;
}
上面的代码生成一个如下所示的文件:
1
1 2 1
118 119 118
119 120 119
120 121 120
1 2 1
0
-1825751608
我在代码中注释了每个fprintf
行的结尾,以显示它显示的数字。
答案 0 :(得分:2)
您正在打印由PyInt_FromLong()
创建的对象的引用计数。你很惊讶它是118(或其他一些值),而不是1。
这是因为Python中的小数字可以“共享”,这意味着每次创建一个小数字时,运行时不需要物理实例化新对象。这是为了提高效率:大多数Python程序创建了一堆数字,如0,1,2,3等等,共享它们可以减少内存消耗和垃圾收集时间。