结论:CPython 以引用计数为主——每个对象维护计数,归零立即释放(确定性析构);以分代循环检测为辅——引用计数解决不了循环引用,gc 模块定期扫描容器对象(list、dict、class 实例等可能成环的类型),用"减去内部引用后是否可达"的标记清除算法回收环。

展开:引用计数的优缺点要会背:优点是对象死亡即回收、内存及时归还、暂停时间短;代价是每次赋值都要维护计数(性能开销),且无法识别循环引用——a.x = b; b.x = a 后两者计数都 ≥1,外界断开后永不归零。分代回收的优化思想是弱分代假说:大部分对象朝生夕死,活过越多次扫描的对象越可能继续存活,所以把对象分三代,第 0 代频繁扫、老年代少扫,用分配与回收差值作触发阈值(默认 700 等,gc.get_threshold() 可查)。工程实践:1)大量临时对象的性能敏感代码可临时 gc.disable()gc.freeze()(3.7+,把启动期对象永久移出扫描);2)排查内存增长用 gc.get_objects() + objgraph 找引用环;3)__del__ 在循环引用中的析构顺序历史上是雷区(PEP 442 后缓解但仍应避免依赖)。

import gc
a, b = [], []
a.append(b); b.append(a)   # 循环引用
del a, b
gc.collect()               # 引用计数无法回收,分代 GC 回收

追问方向:弱引用 weakref 为何能打破循环(不计入计数)、__slots__ 对 gc 跟踪的影响。