On this page
支持循环垃圾收集
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 *尚未被收集器跟踪。
- 调整由PyObject_NewVar()分配的对象的大小。返回调整大小的对象或失败时返回
无效
PyObject_GC_Track
(PyObject ** op *)- 将对象* op *添加到收集器跟踪的一组容器对象中。收集器可能在意外的时间运行,因此在跟踪对象时必须有效。一旦tp_traverse处理程序后面的所有字段都有效(通常在构造函数的结尾附近),则应调用此方法。
同样,对象的解除分配器也必须遵循Pair相似的规则:
在引用其他容器的字段无效之前,必须调用PyObject_GC_UnTrack()。
必须使用PyObject_GC_Del()释放对象的内存。
无效
PyObject_GC_Del
(void ** op *)- 释放使用PyObject_GC_New()或PyObject_GC_NewVar()分配给对象的内存。
无效
PyObject_GC_UnTrack
(void ** op *)- 从收集器跟踪的容器对象集中删除对象* op *。请注意,可以再次在此对象上调用PyObject_GC_Track(),以将其重新添加到跟踪的对象集中。在tp_traverse处理程序使用的任何字段变为无效之前,应为对象调用 deallocator(tp_dealloc处理程序)。
在 3.8 版中进行了更改:_PyObject_GC_TRACK()
和_PyObject_GC_UNTRACK()
宏已从公共 C API 中删除。
tp_traverse处理程序接受以下类型的函数参数:
- int
(*visitproc)
(PyObject *object ,void arg *)- 传递给tp_traverse处理程序的访问者函数的类型。该函数应以要遍历的对象作为* object 来调用,而指向tp_traverse处理函数的第三个参数应作为 arg *来调用。 Python 核心使用多个访问者函数来实现循环垃圾检测;预计用户无需编写自己的访问者Function。
tp_traverse处理程序必须具有以下类型:
- int
(*traverseproc)
(PyObject **self ,visitproc * visit ,void arg *)- 容器对象的遍历函数。实现必须为* self 直接包含的每个对象调用 visit 函数,并将 visit 的参数作为包含的对象,并将 arg 值传递给处理程序。不能使用
NULL
对象参数调用 visit 函数。如果 visit *返回非零值,则应立即返回该值。
- 容器对象的遍历函数。实现必须为* self 直接包含的每个对象调用 visit 函数,并将 visit 的参数作为包含的对象,并将 arg 值传递给处理程序。不能使用
为了简化编写tp_traverse处理程序的过程,提供了一个Py_VISIT()宏。为了使用此宏,tp_traverse实现必须将其参数精确命名为* visit 和 arg *:
- 无效
Py_VISIT
(PyObject ** o *)- 如果* o 不是
NULL
,请使用参数 o 和 arg 调用 visit 回调。如果 visit *返回非零值,则返回它。使用此宏,tp_traverse处理程序如下所示:
- 如果* o 不是
static int
my_traverse(Noddy *self, visitproc visit, void *arg)
{
Py_VISIT(self->foo);
Py_VISIT(self->bar);
return 0;
}
tp_clear处理函数必须为inquiry类型,如果对象是不可变的,则必须为NULL
。
- int
(*inquiry)
(PyObject ** self *)- 删除可能已创建参考周期的参考。不可变对象不必定义此方法,因为它们永远无法直接创建参考循环。请注意,调用此方法后,该对象必须仍然有效(不要仅在引用上调用Py_DECREF())。如果收集器检测到此对象涉及参考周期,则它将调用此方法。