本文档描述了 CPython 的垃圾回收系统,该系统负责在对象不再使用时回收内存。CPython 采用混合内存管理方法,结合了引用计数和循环垃圾回收器。引用计数为大多数对象提供确定性清理,而循环垃圾回收器则处理引用计数本身无法解决的引用循环。
有关内存分配的通用信息,请参阅内存管理。
CPython 的垃圾回收系统包含两个主要组件:
来源
引用计数系统是 CPython 内存管理的基础。每个对象都有一个引用计数,当创建对象的新引用时,该计数会增加,当引用被移除时,该计数会减少。
每个 Python 对象在创建时引用计数为 1。引用计数通过以下操作进行维护:
Py_INCREF(obj):增加对象的引用计数。Py_DECREF(obj):减少对象的引用计数,并可能取消分配对象。Py_XINCREF(obj) 和 Py_XDECREF(obj):安全版本,会检查 NULL 指针。当对象的引用计数达到零时,会调用其取消分配函数(由对象类型在 tp_dealloc 中指定),并释放其内存。
来源
仅靠引用计数无法处理引用循环。考虑这个例子:
在这种情况下,即使 a 和 b 不再能从 Python 代码中访问,它们仍然相互引用,因此它们的引用计数永远不会达到零。这就是循环垃圾回收器发挥作用的地方。
来源
循环垃圾回收器 (GC) 旨在识别和收集组成引用循环但无法从程序中访问的对象。
CPython 的垃圾回收器是分代的,它根据对象在收集周期中的存活情况将对象组织到不同的代中。
在标准的 CPython 实现中:
来源
垃圾回收器仅跟踪可能构成引用循环的对象。这通常包括:
__del__ 方法的对象。不能参与引用循环的对象(如整数、字符串)为提高效率而不被跟踪。
跟踪对象的过程在标准实现和无锁线程实现之间有所不同。
| 标准实现 | 无锁线程实现 |
|---|---|
| 使用 PyGC_Head 结构。 | 使用 ob_gc_bits 字段。 |
| 基于链表的跟踪。 | 基于位标志的跟踪。 |
| _PyObject_GC_TRACK/UNTRACK | _PyObject_SET_GC_BITS |
来源
CPython 中的回收过程遵循以下主要步骤:
gc_refs 字段。gc_refs。gc_refs 非零的对象是可从跟踪对象外部访问的。__del__ 方法)的对象。来源
具有终结器(__del__ 方法)的对象需要特殊处理。如果具有终结器的对象是引用循环的一部分,则没有明显的调用终结器的顺序。
在 CPython 中,当引用循环包含具有终结器的对象时:
DEBUG_SAVEALL,则此类对象将被移至 gc.garbage。来源
随着 Python 3.13 中引入无 GIL 构建选项,实现了一个专门的无锁线程执行垃圾回收器。该回收器与标准实现有几个关键区别:
主要区别包括:
ob_gc_bits 中的位标志,而不是单独的结构。来源
无锁线程构建在某些引用类型上使用延迟引用计数以提高性能。来自堆栈和其他一些源的引用不会立即计数,而是在垃圾回收期间进行处理。
这种方法显著减少了临时引用的引用计数开销,这对于原子操作成本更高的无锁线程环境尤其重要。
来源
CPython 通过 gc 模块公开 GC 功能,同时提供用户控制和诊断功能。
阈值决定了每个世代自动收集的频率。
来源
gc 模块提供了调试功能,以帮助诊断内存泄漏。
当 DEBUG_SAVEALL 设置时,不可收集的对象将被存储在 gc.garbage 中,而不是无引用地留在内存中。
来源
该模块还提供了用于获取已跟踪对象信息和收集统计的功能
来源
在标准实现中,已跟踪对象在内存中的实际对象之前有一个 PyGC_Head 结构
PyGC_Head 包含用于维护每个代对象的双向链表的指针。
在自由线程实现中,跟踪是通过 PyObject 本身的 ob_gc_bits 字段进行的
_PyGC_BITS_TRACKED (1<<0) // Tracked by the GC
_PyGC_BITS_FINALIZED (1<<1) // tp_finalize was called
_PyGC_BITS_UNREACHABLE (1<<2) // Object determined unreachable
_PyGC_BITS_FROZEN (1<<3) // Object should not be collected
_PyGC_BITS_SHARED (1<<4) // Object memory is shared between threads
_PyGC_BITS_ALIVE (1<<5) // Reachable from a known root
_PyGC_BITS_DEFERRED (1<<6) // Use deferred reference counting
来源
当对象分配超过基于对象分配的阈值时,GC 会自动运行
可以使用 gc.collect() 手动触发收集,这对于测试或需要立即回收内存时很有用。
来源
某些对象被标记为“不朽”,不受普通引用计数的约束
不朽对象具有特殊的引用计数,可防止其被解除分配。
来源
采用了多项优化措施,以提高 GC 系统的效率
来源
CPython 的垃圾回收系统结合了引用计数和循环垃圾回收器,以提供高效的内存管理。引用计数系统可以即时处理大部分内存回收,而循环垃圾回收器则负责处理引用计数无法处理的引用循环。
理解这两个组件对于编写内存效率高的 Python 代码至关重要,特别是对于那些可能形成引用循环的长期运行应用程序或处理复杂数据结构的应用程序。
Python 3.13 中引入的自由线程实现增加了复杂机制,使垃圾回收可以在没有全局解释器锁 (Global Interpreter Lock) 的情况下高效运行,从而提高了 Python 应用程序的并行性。
来源