支持循环垃圾收集¶
python对检测和收集垃圾(涉及循环引用)的支持需要对象类型的支持,对象类型是其他对象(也可能是容器)的“容器”。不存储对其他对象的引用,或者只存储对原子类型(如数字或字符串)的引用的类型不需要为垃圾收集提供任何显式支持。
要创建容器类型,请 tp_flags
对象类型的字段必须包括 Py_TPFLAGS_HAVE_GC
并提供 tp_traverse
处理程序。如果类型的实例是可变的,则 tp_clear
还必须提供实施。
- Py_TPFLAGS_HAVE_GC
具有此标志集的类型的对象必须符合此处记录的规则。为了方便起见,这些对象将被称为容器对象。
容器类型的构造函数必须符合两个规则:
必须使用
PyObject_GC_New()
或PyObject_GC_NewVar()
.一旦初始化可能包含对其他容器的引用的所有字段,它必须调用
PyObject_GC_Track()
.
-
TYPE *PyObject_GC_New(TYPE, PyTypeObject *type)¶
类似于
PyObject_New()
但对于容器对象Py_TPFLAGS_HAVE_GC
标志集。
-
TYPE *PyObject_GC_NewVar(TYPE, PyTypeObject *type, Py_ssize_t size)¶
类似于
PyObject_NewVar()
但对于容器对象Py_TPFLAGS_HAVE_GC
标志集。
-
TYPE *PyObject_GC_Resize(TYPE, PyVarObject *op, Py_ssize_t newsize)¶
调整分配对象的大小
PyObject_NewVar()
. 返回已调整大小的对象或NULL
失败论。 op 收集器还不能跟踪。
-
void PyObject_GC_Track(PyObject *op)¶
添加对象 op 到收集器跟踪的容器对象集。收集器可以在意外的时间运行,因此跟踪对象时对象必须有效。这应该在所有字段后跟
tp_traverse
处理程序变为有效的,通常在构造函数末尾附近。
-
int PyObject_GC_IsTracked(PyObject *op)¶
如果对象类型为 op 实现GC协议和 op 垃圾收集器当前正在跟踪,否则为0。
这类似于Python函数
gc.is_tracked()
.3.9 新版功能.
-
int PyObject_GC_IsFinalized(PyObject *op)¶
如果对象类型为 op 实现GC协议和 op 已由垃圾收集器完成,否则为0。
这类似于Python函数
gc.is_finalized()
.3.9 新版功能.
同样,对象的DealLocator必须符合类似的一对规则:
在引用其他容器的字段失效之前,
PyObject_GC_UnTrack()
必须被调用。必须使用以下方法释放对象的内存
PyObject_GC_Del()
.
-
void PyObject_GC_Del(void *op)¶
释放分配给对象的内存
PyObject_GC_New()
或PyObject_GC_NewVar()
.
-
void PyObject_GC_UnTrack(void *op)¶
移除对象 op 从收集器跟踪的容器对象集。注意
PyObject_GC_Track()
可以对该对象再次调用以将其添加回跟踪对象集。解除定位器 (tp_dealloc
handler)应该在tp_traverse
处理程序无效。
在 3.8 版更改: 这个 _PyObject_GC_TRACK()
和 _PyObject_GC_UNTRACK()
宏已从公共C API中删除。
这个 tp_traverse
处理程序接受此类型的函数参数:
-
typedef int (*visitproc)(PyObject *object, void *arg)¶
传递给
tp_traverse
处理程序。应使用要遍历的对象调用函数 object 第三个参数tp_traverse
处理程序组件 arg . python核心使用几个访问者函数来实现循环垃圾检测;用户不需要编写自己的访问者函数。
这个 tp_traverse
处理程序必须具有以下类型:
-
typedef int (*traverseproc)(PyObject *self, visitproc visit, void *arg)¶
容器对象的遍历函数。实现必须调用 参观 直接包含的每个对象的函数 self ,参数为 参观 作为被包含的对象和 arg 传递给处理程序的值。这个 参观 函数不能用
NULL
对象参数。如果 参观 返回一个非零值,该值应立即返回。
简化写作 tp_traverse
处理程序,A Py_VISIT()
提供宏。要使用此宏,请 tp_traverse
实现必须准确命名其参数 参观 和 arg :
-
void Py_VISIT(PyObject *o)¶
如果 o 不是
NULL
调用 参观 回调,带参数 o 和 arg . 如果 参观 返回一个非零值,然后返回它。使用这个宏,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)¶
删除可能已创建引用循环的引用。不可变对象不必定义此方法,因为它们永远不能直接创建引用循环。请注意,调用此方法后,对象必须仍然有效(不要只调用
Py_DECREF()
参考)。如果收集器检测到该对象涉及引用循环,则将调用此方法。