支持循环垃圾回收

Python 对检测和收集涉及循环引用的垃圾的支持需要对象类型的支持,这些对象类型是可能也是容器的其他对象的“容器”。不存储对其他对象的引用,或仅存储对原子类型(如数字或字符串)的引用的类型,不需要为垃圾回收提供任何显式支持。

要创建容器类型,类型对象的 tp_flags 字段必须包含 Py_TPFLAGS_HAVE_GC,并提供 tp_traverse 处理程序的实现。如果该类型的实例是可变的,则还必须提供 tp_clear 实现。

Py_TPFLAGS_HAVE_GC

具有此标志设置的类型的对象必须符合此处记录的规则。为方便起见,这些对象将被称为容器对象。

容器类型的构造函数必须符合以下两个规则:

  1. 必须使用 PyObject_GC_NewPyObject_GC_NewVar 分配对象的内存。

  2. 一旦所有可能包含对其他容器的引用的字段都被初始化,它必须调用 PyObject_GC_Track()

同样,对象的释放器必须符合类似的一对规则:

  1. 在使引用其他容器的字段失效之前,必须调用 PyObject_GC_UnTrack()

  2. 必须使用 PyObject_GC_Del() 释放对象的内存。

    警告

    如果类型添加了 Py_TPFLAGS_HAVE_GC,那么它必须至少实现一个 tp_traverse 处理程序,或者显式使用其子类或子类的处理程序。

    当调用 PyType_Ready() 或一些间接调用它的 API(如 PyType_FromSpecWithBases()PyType_FromSpec())时,如果该类型继承自实现了垃圾回收器协议的类,并且子类包含 Py_TPFLAGS_HAVE_GC 标志,则解释器将自动填充 tp_flagstp_traversetp_clear 字段。

PyObject_GC_New(TYPE, typeobj)

类似于 PyObject_New,但用于设置了 Py_TPFLAGS_HAVE_GC 标志的容器对象。

PyObject_GC_NewVar(TYPE, typeobj, size)

类似于 PyObject_NewVar,但用于设置了 Py_TPFLAGS_HAVE_GC 标志的容器对象。

PyObject *PyUnstable_Object_GC_NewWithExtraData(PyTypeObject *type, size_t extra_size)
这是 不稳定 API。它可能会在次要版本中更改,恕不另行通知。

类似于 PyObject_GC_New,但在对象末尾(偏移量 tp_basicsize 处)分配 *extra_size* 字节。分配的内存初始化为零,除了 Python 对象

额外的数据将随对象一起释放,但 Python 不会管理它。

警告

该函数被标记为不稳定,因为尚未确定在实例之后保留额外数据的最终机制。对于分配可变数量的字段,请首选使用 PyVarObjecttp_itemsize

在 3.12 版本中添加。

PyObject_GC_Resize(TYPE, op, newsize)

调整由 PyObject_NewVar 分配的对象的大小。返回类型为 TYPE*(指代任何 C 类型)的调整大小后的对象,或失败时返回 NULL

op 的类型必须为 PyVarObject*,并且尚未被收集器跟踪。newsize 的类型必须为 Py_ssize_t

void PyObject_GC_Track(PyObject *op)
属于 稳定 ABI 的一部分。

将对象 op 添加到收集器跟踪的容器对象集合中。收集器可能会在意外的时间运行,因此对象在被跟踪时必须有效。这应在 tp_traverse 处理程序之后的所有字段变为有效后调用,通常在构造函数的末尾附近。

int PyObject_IS_GC(PyObject *obj)

如果对象实现了垃圾回收器协议,则返回非零值,否则返回 0。

如果此函数返回 0,则该对象不能被垃圾回收器跟踪。

int PyObject_GC_IsTracked(PyObject *op)
自 3.9 版本以来,属于 稳定 ABI 的一部分。

如果 op 的对象类型实现了 GC 协议,并且 op 当前正在被垃圾回收器跟踪,则返回 1,否则返回 0。

这类似于 Python 函数 gc.is_tracked()

在 3.9 版本中添加。

int PyObject_GC_IsFinalized(PyObject *op)
自 3.9 版本以来,属于 稳定 ABI 的一部分。

如果 op 的对象类型实现了 GC 协议,并且 op 已经被垃圾回收器最终确定,则返回 1,否则返回 0。

这类似于 Python 函数 gc.is_finalized()

在 3.9 版本中添加。

void PyObject_GC_Del(void *op)
属于 稳定 ABI 的一部分。

释放使用 PyObject_GC_NewPyObject_GC_NewVar 分配给对象的内存。

void PyObject_GC_UnTrack(void *op)
属于 稳定 ABI 的一部分。

从垃圾回收器跟踪的容器对象集合中移除对象 *op*。请注意,可以再次对该对象调用 PyObject_GC_Track(),将其添加回跟踪对象集合。析构函数(tp_dealloc 处理程序)应在 tp_traverse 处理程序使用的任何字段变为无效之前,为对象调用此函数。

在 3.8 版本中变更: _PyObject_GC_TRACK()_PyObject_GC_UNTRACK() 宏已从公共 C API 中删除。

tp_traverse 处理程序接受此类型的函数参数

typedef int (*visitproc)(PyObject *object, void *arg)
属于 稳定 ABI 的一部分。

传递给 tp_traverse 处理程序的访问者函数的类型。该函数应使用要遍历的对象作为 *object* 和传递给 tp_traverse 处理程序的第三个参数作为 *arg* 来调用。Python 核心使用多个访问者函数来实现循环垃圾检测;用户不应需要编写自己的访问者函数。

tp_traverse 处理程序必须具有以下类型

typedef int (*traverseproc)(PyObject *self, visitproc visit, void *arg)
属于 稳定 ABI 的一部分。

容器对象的遍历函数。实现必须为 *self* 直接包含的每个对象调用 *visit* 函数,*visit* 的参数是包含的对象和传递给处理程序的 *arg* 值。*visit* 函数不得使用 NULL 对象参数调用。如果 *visit* 返回非零值,则应立即返回该值。

为了简化编写 tp_traverse 处理程序,提供了 Py_VISIT() 宏。为了使用此宏,tp_traverse 实现必须将其参数精确命名为 *visit* 和 *arg*

void Py_VISIT(PyObject *o)

如果 *o* 不是 NULL,则使用参数 *o* 和 *arg* 调用 *visit* 回调。如果 *visit* 返回非零值,则返回该值。使用此宏,tp_traverse 处理程序如下所示

static int
my_traverse(Noddy *self, visitproc visit, void *arg)
{
    Py_VISIT(self->foo);
    Py_VISIT(self->bar);
    return 0;
}

tp_clear 处理程序必须是 inquiry 类型,如果对象是不可变的,则为 NULL

typedef int (*inquiry)(PyObject *self)
属于 稳定 ABI 的一部分。

删除可能已创建引用循环的引用。不可变对象不必定义此方法,因为它们永远无法直接创建引用循环。请注意,在调用此方法后,对象必须仍然有效(不要只在引用上调用 Py_DECREF())。如果垃圾回收器检测到此对象参与了引用循环,它将调用此方法。

控制垃圾回收器状态

C-API 提供了以下函数来控制垃圾回收的运行。

Py_ssize_t PyGC_Collect(void)
属于 稳定 ABI 的一部分。

如果启用了垃圾回收器,则执行完整的垃圾回收。(请注意,gc.collect() 会无条件运行它。)

返回已回收和无法回收的不可达对象的数量。如果垃圾回收器被禁用或已在回收中,则立即返回 0。垃圾回收期间的错误将传递给 sys.unraisablehook。此函数不会引发异常。

int PyGC_Enable(void)
自 3.10 版本起为 Stable ABI 的一部分。

启用垃圾回收器:类似于 gc.enable()。返回之前的状态,0 表示禁用,1 表示启用。

在 3.10 版本中添加。

int PyGC_Disable(void)
自 3.10 版本起为 Stable ABI 的一部分。

禁用垃圾回收器:类似于 gc.disable()。返回之前的状态,0 表示禁用,1 表示启用。

在 3.10 版本中添加。

int PyGC_IsEnabled(void)
自 3.10 版本起为 Stable ABI 的一部分。

查询垃圾回收器的状态:类似于 gc.isenabled()。返回当前状态,0 表示禁用,1 表示启用。

在 3.10 版本中添加。

查询垃圾回收器状态

C-API 提供了以下接口来查询有关垃圾回收器的信息。

void PyUnstable_GC_VisitObjects(gcvisitobjects_t callback, void *arg)
这是 不稳定 API。它可能会在次要版本中更改,恕不另行通知。

在所有活动的、支持垃圾回收的对象上运行提供的 *callback*。*arg* 会传递给 *callback* 的所有调用。

警告

如果回调分配(释放)了新对象,则它们是否会被访问是不确定的。

操作期间会禁用垃圾回收。在回调中显式运行垃圾回收可能会导致未定义的行为,例如多次访问相同对象或完全不访问。

在 3.12 版本中添加。

typedef int (*gcvisitobjects_t)(PyObject *object, void *arg)

要传递给 PyUnstable_GC_VisitObjects() 的访问器函数的类型。arg 与传递给 PyUnstable_GC_VisitObjectsarg 相同。返回 0 继续迭代,返回 1 停止迭代。其他返回值目前保留,因此返回其他任何值的行为是未定义的。

在 3.12 版本中添加。