use*_*143 5 python python-c-api automatic-ref-counting
我只是想了解在使用Python C API时如何处理引用计数.
我想用C++调用Python函数,如下所示:
PyObject* script;
PyObject* scriptRun;
PyObject* scriptResult;
// import module
script = PyImport_ImportModule("pythonScript");
// get function objects
scriptRun = PyObject_GetAttrString(script, "run");
// call function without/empty arguments
scriptResult = PyObject_CallFunctionObjArgs(scriptRun, NULL);
if (scriptResult == NULL)
cout << "scriptResult = null" << endl;
else
cout << "scriptResult != null" << endl;
cout << "print reference count: " << scriptResult->ob_refcnt << endl;
Run Code Online (Sandbox Code Playgroud)
pythonScript.py中的Python代码非常简单:
def run():
return 1
Run Code Online (Sandbox Code Playgroud)
"PyObject_CallFunctionObjArgs"的文档说您获得了一个新的引用作为返回值.所以我希望"scriptResult"的引用计数为1.但是输出是:
scriptResult != null
print reference count: 72
Run Code Online (Sandbox Code Playgroud)
此外,如果我在循环中执行此操作而不减少引用计数,我会期望内存泄漏.然而,这似乎不会发生.
有人可以帮我理解吗?
亲切的问候!
令人困惑的是,小整数(还有True, False, None, 单字符串等)被嵌入(“is”运算符对整数的行为出乎意料),这意味着无论在程序中使用或获取它们的任何地方,运行时都将尝试使用相同的对象实例:
>>> 1 is 1
True
>>> 1 + 1 is 2
True
>>> 1000 + 1 is 1001
False
Run Code Online (Sandbox Code Playgroud)
这意味着当您编写 时return 1,您将返回一个已经存在的int对象实例(如您所见)相当多的引用计数。因为在其他地方使用了相同的实例,如果不取消引用它不会导致内存泄漏。
如果您将脚本更改为return 1001或 ,return object()您将看到初始引用计数为 1 和内存泄漏。
ecatmur 是对的,数字和字符串都在 Python 中,所以你可以尝试使用一个简单的object()对象。
一个简单的演示gc:
import gc
def run():
return 1
s = run()
print len(gc.get_referrers(s)) # prints a rather big number, 41 in my case
obj = object()
print len(gc.get_referrers(obj)) # prints 1
lst = [obj]
print len(gc.get_referrers(obj)) # prints 2
lst = []
print len(gc.get_referrers(obj)) # prints 1 again
Run Code Online (Sandbox Code Playgroud)
多说一点:当 CPython 创建一个新对象时,它会调用 C 宏_Py_NewReference将引用计数初始化为 1。然后使用Py_INCREF(op)和Py_DECREF(op)来增加和减少引用计数。