ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
### 导航 - [索引](../genindex.xhtml "总目录") - [模块](../py-modindex.xhtml "Python 模块索引") | - [下一页](apiabiversion.xhtml "API 和 ABI 版本管理") | - [上一页](typeobj.xhtml "Type 对象") | - ![](https://box.kancloud.cn/a721fc7ec672275e257bbbfde49a4d4e_16x16.png) - [Python](https://www.python.org/) » - zh\_CN 3.7.3 [文档](../index.xhtml) » - [Python/C API 参考手册](index.xhtml) » - [对象实现支持](objimpl.xhtml) » - $('.inline-search').show(0); | # 使对象类型支持循环垃圾回收 Python 对循环引用的垃圾检测与回收需要“容器”对象类型的支持,此类型的容器对象中可能包含其它容器对象。不保存其它对象的引用的类型,或者只保存原子类型(如数字或字符串)的引用的类型,不需要显式提供垃圾回收的支持。 若要创建一个容器类,类型对象的 [`tp_flags`](typeobj.xhtml#c.PyTypeObject.tp_flags "PyTypeObject.tp_flags") 字段必须包含 [`Py_TPFLAGS_HAVE_GC`](typeobj.xhtml#Py_TPFLAGS_HAVE_GC "Py_TPFLAGS_HAVE_GC") 并提供一个 [`tp_traverse`](typeobj.xhtml#c.PyTypeObject.tp_traverse "PyTypeObject.tp_traverse") 处理的实现。如果该类型的实例是可变的,还需要实现 [`tp_clear`](typeobj.xhtml#c.PyTypeObject.tp_clear "PyTypeObject.tp_clear") 。 `Py_TPFLAGS_HAVE_GC`设置了此标志位的类型的对象必须符合此处记录的规则。为方便起见,下文把这些对象称为容器对象。 容器类型的构造函数必须符合两个规则: 1. 必须使用 [`PyObject_GC_New()`](#c.PyObject_GC_New "PyObject_GC_New") 或 [`PyObject_GC_NewVar()`](#c.PyObject_GC_NewVar "PyObject_GC_NewVar") 为这些对象分配内存。 2. 初始化了所有可能包含其他容器的引用的字段后,它必须调用 [`PyObject_GC_Track()`](#c.PyObject_GC_Track "PyObject_GC_Track") 。 TYPE\* `PyObject_GC_New`(TYPE, [PyTypeObject](type.xhtml#c.PyTypeObject "PyTypeObject") *\*type*)类似于 [`PyObject_New()`](allocation.xhtml#c.PyObject_New "PyObject_New") ,适用于设置了 [`Py_TPFLAGS_HAVE_GC`](typeobj.xhtml#Py_TPFLAGS_HAVE_GC "Py_TPFLAGS_HAVE_GC") 标签的容器对象。 TYPE\* `PyObject_GC_NewVar`(TYPE, [PyTypeObject](type.xhtml#c.PyTypeObject "PyTypeObject") *\*type*, Py\_ssize\_t *size*)类似于 [`PyObject_NewVar()`](allocation.xhtml#c.PyObject_NewVar "PyObject_NewVar") ,适用于设置了 [`Py_TPFLAGS_HAVE_GC`](typeobj.xhtml#Py_TPFLAGS_HAVE_GC "Py_TPFLAGS_HAVE_GC") 标签的容器对象。 TYPE\* `PyObject_GC_Resize`(TYPE, [PyVarObject](structures.xhtml#c.PyVarObject "PyVarObject") *\*op*, Py\_ssize\_t *newsize*)为 [`PyObject_NewVar()`](allocation.xhtml#c.PyObject_NewVar "PyObject_NewVar") 分配的对象重新设置大小,并返回调整大小后的对象。当重分配失败时返回 *NULL* 。*op* 必须没有被垃圾回收器监控。 void `PyObject_GC_Track`([PyObject](structures.xhtml#c.PyObject "PyObject") *\*op*)把对象 *op* 加入到垃圾回收器跟踪的容器对象中。对象在被回收器跟踪时必须保持有效的,因为回收器可能在任何时候开始运行。在 [`tp_traverse`](typeobj.xhtml#c.PyTypeObject.tp_traverse "PyTypeObject.tp_traverse") 处理前的所有字段变为有效后,必须调用此函数,通常在靠近构造函数末尾的位置。 void `_PyObject_GC_TRACK`([PyObject](structures.xhtml#c.PyObject "PyObject") *\*op*)[`PyObject_GC_Track()`](#c.PyObject_GC_Track "PyObject_GC_Track") 的宏实现版本。它不能被用于扩展模块。 3\.6 版后已移除: 这个宏在 Python 3.8 中被移除。 同样的,对象的释放器必须符合两个类似的规则: 1. 在引用其它容器的字段失效前,必须调用 [`PyObject_GC_UnTrack()`](#c.PyObject_GC_UnTrack "PyObject_GC_UnTrack") 。 2. 必须使用 [`PyObject_GC_Del()`](#c.PyObject_GC_Del "PyObject_GC_Del") 释放对象的内存。 void `PyObject_GC_Del`(void *\*op*)释放对象的内存,该对象初始化时由 [`PyObject_GC_New()`](#c.PyObject_GC_New "PyObject_GC_New") 或 [`PyObject_GC_NewVar()`](#c.PyObject_GC_NewVar "PyObject_GC_NewVar") 分配内存。 void `PyObject_GC_UnTrack`(void *\*op*)从回收器跟踪的容器对象集合中移除 *op* 对象。 请注意可以在此对象上再次调用 [`PyObject_GC_Track()`](#c.PyObject_GC_Track "PyObject_GC_Track") 以将其加回到被跟踪对象集合。 释放器 ([`tp_dealloc`](typeobj.xhtml#c.PyTypeObject.tp_dealloc "PyTypeObject.tp_dealloc") 句柄) 应当在 [`tp_traverse`](typeobj.xhtml#c.PyTypeObject.tp_traverse "PyTypeObject.tp_traverse") 句柄所使用的任何字段失效之前为对象调用此函数。 void `_PyObject_GC_UNTRACK`([PyObject](structures.xhtml#c.PyObject "PyObject") *\*op*)[`PyObject_GC_UnTrack()`](#c.PyObject_GC_UnTrack "PyObject_GC_UnTrack") 的使用宏实现的版本。不能用于扩展模块。 3\.6 版后已移除: 这个宏在 Python 3.8 中被移除。 [`tp_traverse`](typeobj.xhtml#c.PyTypeObject.tp_traverse "PyTypeObject.tp_traverse") 处理接收以下类型的函数形参。 int `(*visitproc)`([PyObject](structures.xhtml#c.PyObject "PyObject") *\*object*, void *\*arg*)传给 [`tp_traverse`](typeobj.xhtml#c.PyTypeObject.tp_traverse "PyTypeObject.tp_traverse") 处理的访问函数的类型。*object* 是容器中需要被遍历的一个对象,第三个形参对应于 [`tp_traverse`](typeobj.xhtml#c.PyTypeObject.tp_traverse "PyTypeObject.tp_traverse") 处理的 *arg* 。Python核心使用多个访问者函数实现循环引用的垃圾检测,不需要用户自行实现访问者函数。 [`tp_traverse`](typeobj.xhtml#c.PyTypeObject.tp_traverse "PyTypeObject.tp_traverse") 处理必须是以下类型: int `(*traverseproc)`([PyObject](structures.xhtml#c.PyObject "PyObject") *\*self*, [visitproc](#c.visitproc "visitproc") *visit*, void *\*arg*)用于容器对象的遍历函数。在函数的实现中,必须对 *self* 容器内直接包含的每个对象调用 *visit* 函数,容器内的对象作为 *visit* 的形参,*arg* 作为参数。不能使用 *NULL* 对象作为 *visit* 函数的参数。如果 *visit* 返回非零值,此函数需要立即返回此非零值。 为了简化 [`tp_traverse`](typeobj.xhtml#c.PyTypeObject.tp_traverse "PyTypeObject.tp_traverse") 处理的实现,Python提供了一个 [`Py_VISIT()`](#c.Py_VISIT "Py_VISIT") 宏。若要使用这个宏,必须把 [`tp_traverse`](typeobj.xhtml#c.PyTypeObject.tp_traverse "PyTypeObject.tp_traverse") 的参数命名为 *visit* 和 *arg* 。 void `Py_VISIT`([PyObject](structures.xhtml#c.PyObject "PyObject") *\*o*)如果 *o* 不是 *NULL* ,则调用 *visit* 回调函数,并把 *o* 和 *arg* 作为回调函数的参数。如果 *visit* 返回一个非零值,则把此非零值返回上层调用。在使用此宏后, [`tp_traverse`](typeobj.xhtml#c.PyTypeObject.tp_traverse "PyTypeObject.tp_traverse") 处理组织为以下形式: ``` static int my_traverse(Noddy *self, visitproc visit, void *arg) { Py_VISIT(self->foo); Py_VISIT(self->bar); return 0; } ``` The [`tp_clear`](typeobj.xhtml#c.PyTypeObject.tp_clear "PyTypeObject.tp_clear") handler must be of the [`inquiry`](#c.inquiry "inquiry") type, or *NULL*if the object is immutable. int `(*inquiry)`([PyObject](structures.xhtml#c.PyObject "PyObject") *\*self*)丢弃产生循环引用的引用。不可变对象不需要声明此方法,因为他们不可能直接产生循环引用。需要注意的是,对象在调用此方法后必须仍是有效的(不能对引用只调用 [`Py_DECREF()`](refcounting.xhtml#c.Py_DECREF "Py_DECREF") 方法)。当垃圾回收器检测到该对象在循环引用中时,此方法会被调用。 ### 导航 - [索引](../genindex.xhtml "总目录") - [模块](../py-modindex.xhtml "Python 模块索引") | - [下一页](apiabiversion.xhtml "API 和 ABI 版本管理") | - [上一页](typeobj.xhtml "Type 对象") | - ![](https://box.kancloud.cn/a721fc7ec672275e257bbbfde49a4d4e_16x16.png) - [Python](https://www.python.org/) » - zh\_CN 3.7.3 [文档](../index.xhtml) » - [Python/C API 参考手册](index.xhtml) » - [对象实现支持](objimpl.xhtml) » - $('.inline-search').show(0); | © [版权所有](../copyright.xhtml) 2001-2019, Python Software Foundation. Python 软件基金会是一个非盈利组织。 [请捐助。](https://www.python.org/psf/donations/) 最后更新于 5月 21, 2019. [发现了问题](../bugs.xhtml)? 使用[Sphinx](http://sphinx.pocoo.org/)1.8.4 创建。