Python引用计数:为什么Py_REFCNT(o)=1?

2024-03-29 15:16:03 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在试图追踪pythoncc扩展中的内存泄漏,但是我很难理解为什么我的代码会给出引用计数。在

参考下面的代码示例,我想了解以下内容:

  1. 为什么块2中的引用计数从118开始而不是1?(请注意,块2对块1使用了不同的变量。)
  2. 为什么块4中的参考计数从120开始而不是1?(请注意,块4使用与块1相同的变量名。)
  3. 既然块4中的引用计数不是从1开始的,为什么现在在块5的开头是1?在
  4. 最后打印的数字似乎是一个内存地址。为什么它不打印引用计数0?在

下面是一个简短的代码示例。 (我在Windows10上使用64位Python2.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;
}

上面的代码生成一个如下所示的文件:

^{pr2}$

我在代码中的每一行fprintf的末尾添加了注释,以显示它显示的数字。在


Tags: 代码pyblockint计数pydictfidwhy
1条回答
网友
1楼 · 发布于 2024-03-29 15:16:03

您正在打印由PyInt_FromLong()创建的对象的引用计数。您很惊讶它是118(或其他值),而不是1。在

这是因为Python中的小数字可以是“共享”的,这意味着运行时不需要每次创建一个小数字时都实际实例化一个新对象。这是为了提高效率:大多数Python程序都会创建一组数字,比如0、1、2、3等等,共享它们可以减少内存消耗和垃圾收集时间。在

相关问题 更多 >