
python 垃圾收集器(gc)能自动检测并回收不可达的循环引用对象,但仅当这些对象完全脱离程序引用链(即无外部强引用)时才会触发;单纯构造循环引用(如 a → b → a)并不会立即回收,也不会影响对象正常使用。
在 Python 中,内存管理主要依赖引用计数(Reference Counting)为主、循环垃圾收集器(gc 模块)为辅的双重机制。引用计数实时高效,但无法处理循环引用(如列表互相包含对方);而 gc 模块则专门负责周期性扫描和回收那些“不可达但存在内部引用循环”的对象。
以你提供的代码为例:
a = [1, 2, 3] b = [a, a] a.append(b)
执行后,内存结构形成一个双向引用环:
- a 是一个列表 [1, 2, 3, b],其中第四个元素指向 b;
- b 是一个包含两个 a 引用的列表(即 [a, a]),因此 b 持有对 a 的两个强引用;
- 同时,变量名 a 和 b 分别持有对两个列表的顶层引用。
此时,两个对象均被至少一个外部变量直接引用(a 和 b 都存活),因此它们是“可达的”(reachable)。即使存在 a → b → a 的循环,Python 不会回收任何对象——因为 GC 只清理“不可达的循环”,而非“所有循环”。
立即学习“Python免费学习笔记(深入)”;
✅ 正确理解关键点:
- del a 后:a 的名字绑定被移除,但 b 仍持有对原列表的引用,该列表依然可通过 b[0] 访问,因此不回收;
- del b 后:外部变量全部消失,仅剩 a ↔ b 内部互指,此时整个循环结构不可达,下一次 gc.collect()(通常自动触发)将识别并安全回收两个列表;
- b 并不“复制” a,而是存储对 a 的引用(即内存地址),因此 a 若未被回收,b[0] is b[1] 为 True,且修改 a 会反映在 b 中。
⚠️ 注意事项:
- 默认情况下,CPython 的 gc 是启用的,但可手动控制:import gc; gc.disable();
- 可通过 gc.get_referents(obj) 和 gc.get_referrers(obj) 辅助调试引用关系;
- 自定义类若定义了 __del__ 方法,参与循环引用时可能延迟回收(因 __del__ 执行顺序不确定),建议避免在 __del__ 中引发新引用或依赖其他对象状态;
- 对于大量短生命周期小对象,循环引用影响极小;真正需关注的是长期驻留的大对象(如缓存、图结构、ORM 实例等)形成的隐式循环。
总结:Python 的 GC 不会“主动破坏”正在使用的对象。循环引用本身不是 bug,只有当它导致内存泄漏(即对象本该被释放却因循环而滞留)时才需干预——此时应优先考虑使用 weakref 打破强引用环,而非依赖 GC 被动清理。










