使对象类型支持循环垃圾回收¶
Python 对循环引用的垃圾检测与回收需要“容器”对象类型的支持,此类型的容器对象中可能包含其它容器对象。不保存其它对象的引用的类型,或者只保存原子类型(如数字或字符串)的引用的类型,不需要显式提供垃圾回收的支持。
要创建一个容器类,类型对象的 tp_flags
字段必须包括 Py_TPFLAGS_HAVE_GC
并提供一个 tp_traverse
处理句柄的实现。 如果该类型的实例是可变的,则还必须提供 tp_clear
的实现。
Py_TPFLAGS_HAVE_GC
设置了此标志位的类型的对象必须符合此处记录的规则。为方便起见,下文把这些对象称为容器对象。
容器类型的构造函数必须符合两个规则:
该对象的内在必须使用
PyObject_GC_New
或PyObject_GC_NewVar
来分配。初始化了所有可能包含其他容器的引用的字段后,它必须调用
PyObject_GC_Track()
。
同样的,对象的释放器必须符合两个类似的规则:
在引用其它容器的字段失效前,必须调用
PyObject_GC_UnTrack()
。必须使用
PyObject_GC_Del()
释放对象的内存。警告
如果一个类型添加了 Py_TPFLAGS_HAVE_GC,则它 必须 实现至少一个
tp_traverse
句柄或显式地使用来自其一个或多个子类的句柄。当调用
PyType_Ready()
或者某些间接调用该函数的 API 如PyType_FromSpecWithBases()
或PyType_FromSpec()
时解释器将自动填充tp_flags
,tp_traverse
和tp_clear
字段,如果该类型是继承自实现了垃圾回收器协议的类并且该子类 没有 包括Py_TPFLAGS_HAVE_GC
旗标的话。
-
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
类似但会在对象的末尾分配 extra_size 个字节(在tp_basicsize
偏移量处)。 除Python 对象标头
外,分配的内存将初始化为零。附加数据将与对象一起被释放,但在其他情况下则不会由 Python 来管理。
警告
此函数被标记为非稳定的因为在实例之后保留附加数据的机制尚未确定。 要分配可变数量的字段,推荐改用
PyVarObject
和tp_itemsize
。在 3.12 版本加入.
-
TYPE *PyObject_GC_Resize(TYPE, PyVarObject *op, Py_ssize_t newsize)¶
重新调整
PyObject_NewVar
所分配对象的大小。 返回调整大小后的对象或在失败时返回NULL
。 op 必须尚未被垃圾回收器追踪。
-
void PyObject_GC_Track(PyObject *op)¶
- 属于 稳定 ABI.
把对象 op 加入到垃圾回收器跟踪的容器对象中。对象在被回收器跟踪时必须保持有效的,因为回收器可能在任何时候开始运行。在
tp_traverse
处理前的所有字段变为有效后,必须调用此函数,通常在靠近构造函数末尾的位置。
-
int PyObject_GC_IsTracked(PyObject *op)¶
- 属于 稳定 ABI 自 3.9 版开始.
如果 op 对象的类型实现了 GC 协议且 op 目前正被垃圾回收器追踪则返回 1, 否则返回 0。
这类似于 Python 函数
gc.is_tracked()
。在 3.9 版本加入.
-
int PyObject_GC_IsFinalized(PyObject *op)¶
- 属于 稳定 ABI 自 3.9 版开始.
如果 op 对象的类型实现了 GC 协议且 op 已经被垃圾回收器终结则返回 1, 否则返回 0。
这类似于 Python 函数
gc.is_finalized()
。在 3.9 版本加入.
-
void PyObject_GC_Del(void *op)¶
- 属于 稳定 ABI.
使用
PyObject_GC_New
或PyObject_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
处理的实现,Python提供了一个 Py_VISIT()
宏。若要使用这个宏,必须把 tp_traverse
的参数命名为 visit 和 arg 。
-
void Py_VISIT(PyObject *o)¶
如果 o 不为
NULL
,则调用 visit 回调函数,附带参数 o 和 arg。 如果 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)¶
- 属于 稳定 ABI 自 3.10 版开始.
启用垃圾回收器:类似于
gc.enable()
。 返回之前的状态,0 为禁用而 1 为启用。在 3.10 版本加入.
-
int PyGC_Disable(void)¶
- 属于 稳定 ABI 自 3.10 版开始.
禁用垃圾回收器:类似于
gc.disable()
。 返回之前的状态,0 为禁用而 1 为启用。在 3.10 版本加入.
-
int PyGC_IsEnabled(void)¶
- 属于 稳定 ABI 自 3.10 版开始.
查询垃圾回收器的状态:类似于
gc.isenabled()
。 返回当前的状态,0 为禁用而 1 为启用。在 3.10 版本加入.
查询垃圾回收器状态¶
该 C-API 提供了以下接口用于查询有关垃圾回收器的信息。
-
void PyUnstable_GC_VisitObjects(gcvisitobjects_t callback, void *arg)¶
- 这是 不稳定 API。 它可能在微发布版中不带警告地改变。
在全部活动的支持 GC 的对象上运行所提供的 callback。 arg 会被传递给所有 callback 的发起调用。
警告
如果新对象被回调(取消)分配后再被访问其行为是未定义的。
垃圾回收在运行期间被禁用。 在回调中显式地运行回收可能导致未定义的行为,例如多次访问同一对象或完全不访问。
在 3.12 版本加入.
-
typedef int (*gcvisitobjects_t)(PyObject *object, void *arg)¶
要传给
PyUnstable_GC_VisitObjects()
的访问者函数的类型。 arg 与传给PyUnstable_GC_VisitObjects
的 arg 相同。 返回0
以继续迭代,返回1
以停止迭代。 其他返回值目前被保留因此返回任何其他值的行为都是未定义的。在 3.12 版本加入.