ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

时间到Py_INCREF?

2019-11-09 01:58:07  阅读:16  来源: 互联网

标签:cpython memory-management python



我正在开发C扩展,并且正要跟踪内存泄漏.通过阅读Python文档,很难理解何时增加/减少Python对象的引用计数.另外,在花几天时间尝试嵌入Python解释器(以便将该扩展编译为独立程序)之后,我不得不放弃这一努力.因此,像Valgrind这样的工具在这里无能为力.

到目前为止,通过反复试验,我了解到例如Py_DECREF(Py_None)是一件坏事……但这是否对任何常量都适用?我不知道.

到目前为止,我的主要困惑可以这样列出:

>如果PyWhatever_New()创建的内容没有超过创建它的过程,我是否必须减少refcount?
>是否每个Py_INCREF都需要与Py_DECREF匹配,还是应该一个/另一个?
>如果对Python过程的调用导致PyObject *,我是否需要对其进行递增以确保仍可以永久使用它,还是对它进行递减以确保最终将其进行垃圾回收,或者两者都不做?
>是通过C API在堆栈上还是在堆上分配的通过C API创建的Python对象? (例如,Py_INCREF有可能在堆上重新分配它们).
>在将C代码创建的Python对象传递给Python代码之前,是否需要做一些特殊的事情?如果Python代码超过了创建Python对象的C代码,该怎么办?
>最终,我了解到Python同时具有引用计数和垃圾收集器:如果是这样,如果我弄乱了引用计数(即递减得不够多)有多重要,GC最终会弄清楚如何处理那些对象吗?

解决方法:

其中大部分内容涵盖在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 by Py_DECREF, or should there be one more of one / the other?

您自己的代码中的数字不一定是平衡的.总数必须保持平衡,但是Python本身内部会发生增量和减量.例如,任何返回“新引用”的东西都已经完成了inc的注册,而任何“窃取”引用的东西都可以完成该注册.

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对象.而且,如果不将对象的C数组或C字符串转换为Python对象的元组,Python字节或str,就无法将其传递给Python代码.例如,在某些情况下,您可以将指向存储在PyCapsule中的指针的指针存储在PyCapsule中,然后传递该指针,但这与任何C程序都一样,并且……只是不这样做.

Finally, I understand that Python has both reference counting and garbage collector

垃圾收集器只是一个循环破坏器.如果您具有在参考周期中彼此​​保持活动状态的对象,则可以依赖GC.但是,如果您泄漏了对对象的引用,GC将永远不会清理它.



标签:cpython,memory-management,python

专注分享技术,共同学习,共同进步。侵权联系[admin#icode9.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有