【问题标题】:Correct cyclic garbage-collection in extension modules更正扩展模块中的循环垃圾收集
【发布时间】:2012-09-04 00:53:14
【问题描述】:

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

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

  1. 必须使用PyObject_GC_New()PyObject_GC_NewVar() 为对象分配内存。
  2. 一旦所有可能包含对其他容器的引用的字段都被初始化,它必须调用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: 断言“gc->gc.gc_refs != 0”失败。引用计数太小

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

【问题讨论】:

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


    【解决方案1】:

    我本人在 C API 方面经验不足,无法给您任何建议,但 Python 容器实现本身有很多示例

    就我个人而言,我会先从元组实现开始,因为它是不可变的:Objects/tupleobject.c。然后转到dictlistset 实现,以进一步了解可变容器:

    我不禁注意到,自始至终都有对PyObject_GC_New()PyObject_GC_NewVar()PyObject_GC_Track() 的调用,以及设置了Py_TPFLAGS_HAVE_GC

    【讨论】:

    • 感谢您的回复。我正在调查 PyObject_GC_New() API 的某些版本无法正确处理子类型的可能性,这是 AssertionError 的原因。
    【解决方案2】:

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

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

    Noddy documentation says(在本节末尾):

    差不多就是这样。如果我们编写了自定义 tp_alloctp_free 插槽,我们需要修改它们以进行循环垃圾收集。大多数扩展将使用自动提供的版本。

    不幸的是,Supporting Cyclic Garbage Collection documentation 没有明确表明您不需要自己做这件事。


    详情:

    Noddy 是使用一个名为Noddy_new 的函数分配的,该函数位于TypeObjecttp_new 插槽中。根据the documentation,“新”函数应该做的主要事情是调用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,对于具有Py_TPFLAGS_HAVE_GC 的类,它会自动设置为PyObject_GC_DelPyObject_GC_Del 包含与 PyObject_GC_UnTrack 相同的代码,因此无需调用 untrack。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-26
      • 1970-01-01
      • 2018-10-21
      相关资源
      最近更新 更多