python垃圾回收采用引用计数加三色标记思想的标记-清除分代机制,gc模块处理循环引用;对象分三代,按存活时间晋升,第0代最频繁回收;仅容器类型参与gc,流程含暂停计数、标记可达、清除未标记、重置链表;gc不替代引用计数,仅补充处理不可达循环引用。

Python 的垃圾回收(GC)主要依靠引用计数 + 分代回收机制,其中 gc 模块负责管理循环引用——这是引用计数无法处理的部分。源码实现在 CPython 的 Modules/gcmodule.c 中,核心逻辑围绕“三色标记”思想的简化变体(实际为“标记-清除”,非并发 GC)展开,配合分代策略提升效率。
分代机制:按对象存活时间划分回收优先级
CPython 将对象分为三代(0、1、2),新创建对象进入第 0 代;每次第 n 代被回收后,幸存对象晋升到第 n+1 代(最高为第 2 代)。各代有独立计数器(gc_state->generation0/1/2),当某代对象数量超过阈值(如第 0 代默认 700),触发该代及更老代的回收。
- 第 0 代最频繁触发,适合清理短期对象和常见循环引用(如局部作用域中构造的 list/dict 相互引用)
- 第 2 代回收代价高,仅在长期运行或显式调用
gc.collect(2)时才执行 - 可通过
gc.get_threshold()查看当前阈值,gc.set_threshold()动态调整
标记-清除流程:识别并回收不可达循环引用
GC 不扫描所有 Python 对象,只处理“可被 GC 管理”的容器类型(如 list、dict、class 实例等),它们在创建时被链入全局的 gc_list 双向链表。回收流程分四步:
- 暂停引用计数更新:临时禁用部分对象的引用计数变更(避免并发修改干扰标记)
-
标记可达对象:从根集(栈帧变量、全局变量、寄存器等)出发,递归遍历引用链,将所有可达对象打上“已标记”标志(使用对象头中的
gc_next字段复用作标记位) -
清除未标记对象:遍历当前代的
gc_list,对未标记对象调用其tp_dealloc,释放内存并触发__del__(若定义) - 重置链表与计数器:将幸存对象移入下一代链表,更新各代计数器
关键数据结构与钩子支持
每个可 GC 对象需满足:头部包含 PyObject_VAR_HEAD + PyGC_Head(含 gc_next/gc_prev 指针)。CPython 在对象分配时(如 PyObject_GC_New)将其插入全局链表;销毁时(PyObject_GC_Del)移除。
立即学习“Python免费学习笔记(深入)”;
-
gc.callbacks是一个列表,可注册函数监听 GC 事件(如gc.DEBUG_COLLECTABLE输出可回收对象) -
gc.get_objects(generation=0)返回指定代中所有可 GC 对象,用于调试内存泄漏 - 自定义类可通过设置
__slots__ = ()或继承object(而非dict)减少 GC 开销
与引用计数的协同关系
GC 并不替代引用计数,而是补充。绝大多数对象靠引用计数即时释放;GC 仅周期性介入处理“引用计数不为 0 但实际不可达”的循环引用。例如:
a = [] b = [] a.append(b) b.append(a) # 此时 a、b 引用计数均为 2,删除 a/b 后仍为 1,需 GC 清理
注意:gc.disable() 会停用分代回收,但引用计数照常工作;此时循环引用将永久驻留内存,直到解释器退出。










