Python循环引用检测与分代回收详解
请详细解释Python GC如何检测和回收循环引用。分代回收的工作原理是什么?GC的阈值(threshold)如何配置?什么是gc.garbage列表(Python 3.4+已弃用)?如何用gc模块的get_objects和get_referrers调试内存泄漏?
回答
苦行僧
循环引用检测:GC使用标记-清除(mark and sweep)算法。从根对象集合出发,遍历所有可达对象并标记,未被标记的对象即为不可达(可回收)。
分代回收:
- 第0代(年轻代):新创建的对象,频繁扫描
- 第1代:经历一次GC仍存活的对象,较少扫描
- 第2代(老年代):经历多次GC存活的对象,最少扫描
阈值机制:gc.get_threshold()返回(threshold0, multiplier1, multiplier2)。
- 第0代分配对象数 >
threshold0时触发第0代GC - 第0代GC触发了
multiplier1次后触发第1代GC - 第1代GC触发了
multiplier2次后触发第2代GC - 默认:
(700, 10, 10)
调试工具:
import gc
gc.set_debug(gc.DEBUG_LEAK) # 打印泄漏信息
# 查看所有存活对象
objs = gc.get_objects()
# 查看谁引用了特定对象
referrers = gc.get_referrers(my_obj)
gc.garbage:Python 3.4之前存放无法回收的带__del__的循环引用对象,3.4+中__del__不再阻止循环引用回收,该列表已弃用。