- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我正在研究 C 扩展,现在我想追踪内存泄漏。通过阅读 Python 的文档,很难理解何时增加/减少 Python 对象的引用计数。此外,在花了几天时间尝试嵌入 Python 解释器(以便将扩展编译为独立程序)之后,我不得不放弃这项努力。因此,Valgrind 之类的工具在这里无能为力。
到目前为止,通过反复试验,我了解到,例如,Py_DECREF(Py_None)
是一件坏事……但任何常量都是如此吗?我不知道。
到目前为止,我的主要困惑可以这样列出:
PyWhatever_New()
创建的任何东西的生命周期都没有超过创建它的过程,我是否必须减少它的引用计数?Py_INCREF
都需要与 Py_DECREF
匹配,还是应该有一个或另一个?PyObject*
,我是需要递增它以确保我仍然可以(永远)使用它,还是递减它以确保它最终会被垃圾收集,还是两者都不收集?Py_INCREF
可能会在堆上重新分配它们)。最佳答案
Reference Count Details 中涵盖了大部分内容,其余内容包含在有关您提出的具体问题的文档中。但是,要将所有内容集中在一个地方:
Py_DECREF(Py_None)
is a bad thing... but is this true of any constant?
更一般的规则是,在任何你没有得到新的/被盗的引用并且没有调用 Py_INCREF
的东西上调用 Py_DECREF
是不好的事物。由于您永远不会对任何可作为常量访问的内容调用 Py_INCREF
,这意味着您永远不会对它们调用 Py_DECREF
。
Do I have to decrement refcount on anything created by
PyWhatever_New()
是的。任何返回“新引用”的东西都必须递减。按照惯例,任何以 _New
结尾的内容都应该返回一个新的引用,但无论如何都应该对其进行记录(例如,参见 PyList_New
)。
Does every
Py_INCREF
need to be matched byPy_DECREF
, or should there be one more of one / the other?
自己代码中的数字不一定平衡。 总数 必须保持平衡,但在 Python 内部会发生递增和递减。例如,任何返回“新引用”的东西都已经执行了 inc,而任何“窃取”引用的东西都将对其执行 dec。
Are Python objects created through C API on the stack allocated on stack or on heap? (It is possible that Py_INCREF reallocates them on heap for example).
无法通过堆栈上的 C API 创建对象。 C API 只有返回对象指针的函数。
大多数这些对象都分配在堆上。有些实际上在静态内存中。
但是您的代码无论如何都不应该关心。您永远不会分配或删除它们;它们在 PySpam_New
和类似函数中分配,并在您将它们 Py_DECREF
为 0 时自行释放,因此它们在哪里对您来说无关紧要。
(除了常量,您可以通过它们的全局名称访问它们,例如 Py_None
。您显然知道它们在静态存储中。)
Do I need to do anything special to Python objects created in C code before passing them to Python code?
没有。
What if Python code outlives C code that created Python objects?
我不确定这里的“过时”是什么意思。当任何对象依赖于它的代码时,您的扩展模块不会被卸载。 (事实上 ,至少在 3.8 之前,您的模块可能永远不会在关闭之前卸载。)
如果您只是指 _New
返回一个对象的函数,那不是问题。您必须竭尽全力在堆栈上分配任何 Python 对象。如果不将对象的 Python 元组或 Python 字节或 str 转换为 Python 对象元组,则无法将 C 对象数组或 C 字符串之类的东西传递给 Python 代码。在某些情况下,例如,您可以在 PyCapsule
中存储指向堆栈中某物的指针并传递它——但这与任何 C 程序中的相同,并且……只是不要这样做
Finally, I understand that Python has both reference counting and garbage collector
垃圾收集器只是一个循环破坏者。如果您的对象通过引用循环使彼此保持事件状态,则可以依赖 GC。但是,如果您泄漏了对某个对象的引用,GC 将永远不会清理它。
关于python - 什么时候 Py_INCREF?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50336978/
我正在研究 C 扩展,现在我想追踪内存泄漏。通过阅读 Python 的文档,很难理解何时增加/减少 Python 对象的引用计数。此外,在花了几天时间尝试嵌入 Python 解释器(以便将扩展编译为独
以下说法是否正确: 如果在 C 函数中创建了 Python 对象,但该函数不返回它,则不需要 INCREF,但需要一个 DECREF。 [false]如果函数确实返回它,你确实需要INCREF,在接收
我正在学习在 python 中定义“新类型”的教程,https://docs.python.org/2/extending/newtypes.html ,我不明白在这段代码中使用 Py_DECREF
如果您获得借用的引用,但不将其归还给 Python,那么您应该在获得它时执行 Py_INCREF 操作,然后在完成后执行 Py_DECREF 操作有了它,还是这是多余的? 例如,这个简单的示例从 Py
为什么在 C 中返回 Py_None 之前需要 Py_INCREF(Py_None),如下所示? Py_INCREF(Py_None); return Py_None; 如果省略 Py_INCREF(
每当我调用我的函数时,每次调用都会增加大约 +10M 的内存使用量,所以我认为这里存在一些内存泄漏。 .... PyObject *pair = PyTuple_New(2), *item = PyL
我是一名优秀的程序员,十分优秀!