python - 更正扩展模块中的循环垃圾收集

标签 python c garbage-collection python-c-api python-extensions

Python 2.7 文档的两个部分提到为扩展模块中定义的容器对象添加循环垃圾回收 (CGC) 支持。

Python/C API Reference Manual给出两个规则,即,

  1. The memory for the object must be allocated using PyObject_GC_New() or PyObject_GC_NewVar().
  2. Once all the fields which may contain references to other containers are initialized, it must call PyObject_GC_Track().

而在 Extending and Embedding the Python Interpreter ,对于 Noddy 示例,似乎添加 Py_TPFLAGS_HAVE_GC 标志并填充 tp_traversetp_clear 插槽就足够了启用 CGC 支持。并且上面的两个规则根本没有被实践。

当我修改 Noddy 示例以实际遵循 PyObject_GC_New()/PyObject_GC_Del()PyObject_Track() 的规则时/PyObject_GC_UnTrack(),它令人惊讶地引发了断言错误,

Modules/gcmodule.c:348: visit_decref: Assertion "gc->gc.gc_refs != 0" failed. refcount was too small

这让我对实现 CGC 的正确/安全方式感到困惑。任何人都可以提供建议,或者最好提供一个支持 CGC 的容器对象的简洁示例吗?

最佳答案

在大多数正常情况下,您不需要自己进行跟踪/取消跟踪。文档中对此进行了描述,但并未明确说明。在 Noddy example 的情况下你绝对不会。

简短的版本是一个 TypeObject 包含两个函数指针:tp_alloctp_free。默认情况下,tp_alloc 在创建类时调用所有正确的函数(如果设置了 Py_TPFLAGS_HAVE_GC)并且 tp_free 在销毁时取消跟踪类。

Noddy documentation says (在本节末尾):

That’s pretty much it. If we had written custom tp_alloc or tp_free slots, we’d need to modify them for cyclic-garbage collection. Most extensions will use the versions automatically provided.

不幸的是,Supporting Cyclic Garbage Collection documentation 中没有明确表示您不需要自己执行此操作的一个地方是.


详细信息:

Noddy 是使用一个名为 Noddy_new 的函数分配的,该函数放置在 TypeObjecttp_new 槽中。根据the documentation ,"new"函数应该做的主要事情是调用 tp_alloc slot .您通常不会自己编写 tp_alloc,它只是默认为 PyType_GenericAlloc()

查看PyType_GenericAlloc() in the Python source显示了它根据 PyType_IS_GC(type) 更改的许多部分。首先它调用 _PyObject_GC_Malloc 而不是 PyObject_Malloc,然后调用 _PyObject_GC_TRACK(obj)。 [请注意,PyObject_New 真正做的是调用 PyObject_Malloc,然后调用 tp_init。]

同样,在释放时调用 tp_free slot ,自动设置为 PyObject_GC_Del对于具有 Py_TPFLAGS_HAVE_GC 的类。 PyObject_GC_Del 包含与 PyObject_GC_UnTrack 相同的代码,因此无需调用 untrack。

关于python - 更正扩展模块中的循环垃圾收集,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12255537/

相关文章:

c - 如何处理我正在编写的脚本语言中的标签?

c - C 中的简单连接

c - 垃圾收集器和双重分配的内存

java - 未报Full GC时G1 GC暂停时间是什么原因?

javascript - 我可以使用传递给 Rust 的 JavaScript 对象来实现需要垃圾回收的结构吗?

Python 序列化类并使用 JsonPickle 更改属性大小写

python - 如何设置 Pyglet 以在 Colab 中与 Manim 一起工作?

c - Cygwin 的 GCC 与 Windows 上的 MSVC 编译器之间是否存在任何性能问题?

python - 导入 numpy 和 Scipy 包的模块/子包的差异

python - 某些列的 Pandas 平均值