我試圖追查一個Python C擴展中的內存泄漏,並且無法理解爲什麼我的代碼給出了它的引用計數。Python引用計數:爲什麼不是Py_REFCNT(o)= 1?
參照下面的代碼例如,我想了解以下,
- 爲什麼在118在塊2開始的引用計數,而不是1? (注意方塊2對方塊1使用不同的變量。)
- 爲什麼方塊4中的參考計數從120開始而不是1? (請注意,塊4使用與塊1相同的變量名稱。)
- 鑑於塊4中的引用計數不是從1開始的,爲什麼它在塊5的開始時是1?
- 最後打印的號碼似乎是內存地址。爲什麼不打印0的引用計數?
下面是一個簡短的代碼示例。 (我使用的64位的Python 2.7在Windows 10,使用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
行顯示它顯示的數字。
您的最後兩張照片是已經處理的對象的重新計數。沒有這樣的訪問是有效的;沒有意義背後的事實,一個返回零,一個沒有。我相信甚至有可能通過嘗試訪問不再存在的對象來使程序崩潰。 – jasonharper