Python 内存占用持续增长的治理方案

8次阅读

gc.collect() 有时无效是因为对象未被识别为可回收,如含__del__的循环引用或被全局容器持有;应使用tracemalloc定位内存大户,用gc.get_referrers()追踪强引用链。

Python 内存占用持续增长的治理方案

为什么 gc.collect() 有时完全没用

调用 gc.collect() 后内存不降,往往不是垃圾回收器失灵,而是对象根本没被识别为“可回收”——比如循环引用中混入了自定义 __del__ 方法,或对象被全局容器(如模块级 listdict)意外持有。python 的引用计数机制会优先处理无循环的引用,而 gc 模块只负责检测循环引用,且默认不扫描含 __del__ 的对象。

实操建议:

立即学习Python免费学习笔记(深入)”;

  • 先用 gc.set_debug(gc.DEBUG_STATS) 开启统计,观察是否真有未回收对象;
  • 检查是否有类似 cache = [] 这样的模块级变量在持续 append()
  • 避免在类中定义 __del__,改用 weakref.finalize 替代;
  • 对疑似泄漏对象,用 sys.getrefcount(obj)gc.get_referrers(obj) 追踪谁在持有着它。

如何定位真正吃内存的 Python 对象

psutil.Process().memory_info().rss 只能看到进程总内存,无法定位到具体对象。必须下钻到 Python 对象层级。

实操建议:

立即学习Python免费学习笔记(深入)”;

  • tracemalloc 模块(Python 3.4+ 内置):启动时调用 tracemalloc.start(),之后用 tracemalloc.get_top_stats(10) 查看分配最多内存的代码行;
  • 注意 tracemalloc 默认只记录前 256 帧,大项目需提前设 tracemalloc.start(25) # 25MiB 跟踪上限
  • 若怀疑是 numpy/pandas 导致,直接检查 .nbytes.memory_usage(deep=True).sum(),它们常因视图(view)复用底层 buffer 而不释放;
  • 警惕 Logging 模块:如果 handler 持有大量日志 record(尤其用 MemoryHandler),也会拖慢回收。

delNone 赋值的区别在哪

del obj 删除的是名字绑定,不是对象本身;obj = None 是重新绑定,原对象只要还有其他引用就依然存活。两者都不保证立即释放内存,只是移除一个引用路径。

实操建议:

立即学习Python免费学习笔记(深入)”;

  • 对大型临时对象(如读取的大文件内容、DataFrame 中间结果),优先用 del obj + 显式 gc.collect()(仅限关键路径,别滥用);
  • 在函数内创建的大对象,通常无需手动干预——函数返回后局部变量自动解绑,引用计数归零即释放;
  • 若对象被闭包Lambda 或弱引用容器持有,del 无效,得查清持有者再清理;
  • 切勿在循环里频繁调用 gc.collect(),它会暂停所有线程,反而拖慢吞吐。

第三方库引发的隐性内存滞留

requestssqlalchemytorch 这类库常自带连接池、缓存或上下文管理逻辑,表面看没泄漏,实则内部对象长期驻留。例如 requests.session() 默认启用连接池,pool_connections=10 意味着最多保持 10 个空闲连接对象;SQLAlchemyQuery 对象若未显式关闭,其结果集可能延迟释放。

实操建议:

立即学习Python免费学习笔记(深入)”;

  • requests.Session() 时,确保在合适时机调用 session.close(),或用 with session as s: 上下文;
  • SQLAlchemy 中,避免长时间持有 session.query(...).all() 返回的全量 list,改用 yield_per() 流式处理;
  • pytorch 训练中,记得在每个 batch 后调用 loss.detach()del loss, outputs,否则计算图节点持续累积;
  • 所有带缓存的库(如 functools.lru_cache),检查 maxsize 是否设为 None——这等于无限缓存,极易失控。

内存增长问题最难的不是发现,而是确认“谁还在强引用那个本该消失的对象”。越早用 tracemallocgc.get_referrers() 锁定根引用链,越能避开靠猜和重启掩盖问题的习惯。

text=ZqhQzanResources