CPython 以引用计数为主回收内存,但引用计数解决不了循环引用(两个对象互相引用,计数永远不归零)。分代垃圾回收(gc 模块)就是为此设计的补充机制。

分代假设:大多数对象朝生夕死;活得越久的对象越不容易死。GC 把容器对象分为三代(0、1、2),新对象进第 0 代。当"分配数减去回收数"超过该代阈值(默认 0 代约 700)时,触发该代及所有更年轻一代的回收;熬过回收的对象晋升到更老一代。老年代回收频率低,避免反复全量扫描的开销。

循环引用的检测:回收时对该代所有容器对象做一次遍历——把每个对象的计数临时减去"来自本集合内部的引用数",计数归零的是"外部不可达"的候选,再做可达性分析,最终不可达的整组对象即为循环垃圾,统一释放(含互相引用)。

要点:

  • 只有容器类对象(list、dict、tuple、类实例等)纳入 GC 跟踪,纯 int/str 不会循环引用,不参与。
  • 循环引用中的对象若定义了 __del__,旧版本无法回收;3.4 起(PEP 442)可以正常回收,但析构顺序仍需谨慎。
  • 预防手段:用 weakref 弱引用打破环(典型如缓存、观察者模式);gc.disable() / gc.collect() 可手动控制,部分高性能服务会选择关闭自动 GC 定时手动回收。

追问方向:分代阈值调优、弱引用三种形式(ref、proxy、callback)。