wvx*_*xvw 5 python memory-management cpython
我正在开发一个 C 扩展,现在我想追踪内存泄漏。通过阅读 Python 的文档,很难理解何时增加/减少 Python 对象的引用计数。此外,在花了几天时间尝试嵌入 Python 解释器(为了将扩展编译为独立程序)之后,我不得不放弃这项努力。所以,像 Valgrind 这样的工具在这里是无能为力的。
到目前为止,通过反复试验,我了解到,例如,这Py_DECREF(Py_None)
是一件坏事……但这是否适用于任何常数?我不知道。
到目前为止,我的主要困惑可以这样列出:
PyWhatever_New()
如果它不超过创建它的程序,我是否必须减少它创建的任何东西的refcount?Py_INCREF
需要与 匹配Py_DECREF
,还是应该有一个/另一个?PyObject*
,我是否需要增加它以确保我仍然可以使用它(永远),或者减少它以确保最终它会被垃圾收集,或者两者都不需要?Py_INCREF
在堆上重新分配它们)。引用计数详细信息中涵盖了大部分内容中介绍,其余内容在有关您所询问的具体问题的文档中介绍。但是,要将所有内容集中在一处:
\n\n\n\n\n\n
Py_DECREF(Py_None)
是一件坏事……但是对于任何常数都是如此吗?
更一般的规则是,调用Py_DECREF
任何您没有获得新的/被盗的引用并且没有调用的东西Py_INCREF
都是一件坏事。由于您从不调用Py_INCREF
任何可访问的常量,这意味着您从不调用Py_DECREF
它们。
\n\n\n我是否必须减少由以下内容创建的任何内容的引用计数
\nPyWhatever_New()
是的。任何返回“新引用”的内容都必须递减。按照惯例,任何以 结尾的内容都_New
应该返回一个新的引用,但无论如何都应该记录它(例如,请参阅PyList_New
)。
\n\n\n是否每个都
\nPy_INCREF
需要与 匹配Py_DECREF
,还是应该有一个/另一个的多个?
你自己的代码中的数字不一定是平衡的。总数必须平衡,但 Python 本身内部会发生增量和减量。例如,任何返回“新引用”的内容都已经执行了 inc,而任何“窃取”引用的内容都将对其执行 dec。
\n\n\n\n\n通过 C API 在堆栈上创建的 Python 对象是分配在堆栈上还是堆上?(例如,Py_INCREF 可能会在堆上重新分配它们)。
\n
无法通过堆栈上的 C API 创建对象。C API 仅具有返回对象指针的函数。
\n\n这些对象大部分都分配在堆上。有些实际上位于静态内存中。
\n\n但无论如何你的代码不应该关心。您永远不会分配或删除它们;它们在 和类似的函数中分配PySpam_New
,并在您将它们设置为 0 时自行释放Py_DECREF
,因此它们在哪里对您来说并不重要。
(例外的是您可以通过全局名称访问的常量,例如Py_None
。您显然知道这些常量位于静态存储中。)
\n\n\n在将 C 代码中创建的 Python 对象传递给 Python 代码之前,我是否需要对其执行任何特殊操作?
\n
不。
\n\n\n\n\n如果 Python 代码比创建 Python 对象的 C 代码寿命更长怎么办?
\n
我不确定你所说的“寿命长”是什么意思。当任何对象依赖于其代码时,您的扩展模块将不会被卸载。(事实上,至少在 3.8 之前,您的模块在关闭之前可能永远不会被卸载。)
\n\n如果您只是指返回一个对象的函数_New
,那不是问题。您必须不遗余力地在堆栈上分配任何 Python 对象。如果不将 C 对象数组或 C 字符串等内容转换为 Python 对象元组或 Python 字节或字符串,则无法将它们传递到 Python 代码中。在某些情况下,例如,您可以将指向堆栈上某些内容的指针存储在 a 中PyCapsule
并传递该 xe2x80x94 但这与任何 C 程序中的相同,并且 xe2x80xa6 只是不要这样做。
\n\n\n终于明白Python既有引用计数又有垃圾收集器了
\n
垃圾收集器只是一个循环断路器。如果您的对象通过引用循环使彼此保持活动状态,则可以依靠 GC。但如果您泄漏了对某个对象的引用,GC 将永远不会清理它。
\n 归档时间: |
|
查看次数: |
1295 次 |
最近记录: |