`gc` 是否像对待 `__del__` 一样对待 Cython 的 `__dealloc__`?

Does `gc` treat Cython's `__dealloc__` similarly to `__del__`?

Python 的可选垃圾收集器 gc ignores cycles that contain any object with a __del__ method:

Changed in version 3.4: Following PEP 442, objects with a __del__() method don’t end up in gc.garbage anymore.

Cython 扩展类型可以有一个 __dealloc__ 方法,但是 no __del__ method:

Note: There is no __del__() method for extension types.

为了收集循环,垃圾收集器是否将 __dealloc__ 的存在视为存在 __del__ 方法?或者 __dealloc__ 对垃圾收集器不可见?

如果查看生成的 C 代码,您会发现 Cython 在 tp_dealloc 槽中生成析构函数,而不是 tp_del

cdef class B:
    def __dealloc__(self):
        pass

生成:

static PyTypeObject __pyx_type_5cy_gc_B = {
  PyVarObject_HEAD_INIT(0, 0)
  "cy_gc.B", /*tp_name*/
  sizeof(struct __pyx_obj_5cy_gc_B), /*tp_basicsize*/
  0, /*tp_itemsize*/
  __pyx_tp_dealloc_5cy_gc_B, /*tp_dealloc*/

  /* lines omitted */

  0, /*tp_del*/
  0, /*tp_version_tag*/
  #if PY_VERSION_HEX >= 0x030400a1
  0, /*tp_finalize*/
  #endif
};

您可以轻松验证其他示例也是如此(例如 类 自动生成 __dealloc__)。

Therefore, for Python 3.4+:

Starting with Python 3.4, this list should be empty most of the time, except when using instances of C extension types with a non-NULL tp_del slot.

Cython 类 不应该出现在这个无法收集的东西列表中,因为它们没有 tp_del 定义。


对于 Python 的早期版本,我认为您也可以。主要是因为您仍然没有 __del__ 方法,而且还因为 cython automatically generates tp_traverse and tp_clear functions 应该允许 Python 打破引用循环涉及 Cython 类.

您可以禁用这些 tp_traversetp_clear 函数的生成。我不太清楚引用循环中的对象会发生什么,但没有检测或破坏它的方法。它们很可能只是继续存在于某个地方,但无法访问。


我认为问题(在 Python 3.4 之前)是 __del__ 方法可以使对象再次可访问:

class C:
   def __del__(self):
      global x
      x = self

__dealloc__ 在 no return 之后被调用,所以这是不允许的(如果你访问 x,你只会得到一个段错误)。因此,它们不必陷入 gc.garbage 的不确定状态。