Python内存泄漏 —— 宏观篇
应该弄清楚哪些问题
- 内存情况如何,是否一直增长?
- 哪些是异常对象?这类对象占总内存多大比例?
- 异常对象为何泄漏?如何使其正常释放?
- 如何确定异常对象正常释放了?如何防止其后续再次出现类似问题?
内存增长情况
先确定服务内存总体占用情况,如果发现内存占用曲线总体上一直上升,则说明很可能存在内存泄漏问题(具体要结合业务特点)。
确定异常对象情况
确定异常对象
有很多方法可以使用,推荐简单的objgraph
使用objgraph.growth
可以定位到内存增长的情况
确定异常对象内存总体占比
确定异常对象后,此时着急上手解决问题,可能出现一顿操作猛如虎,一看效果原地杵。这样虽然能单点击破一些问题,但总体内存走势并不一定会有改善,因为解决的这个对象占总体内存比例可能很小。试想解决了占比1%的内存泄漏对象,对总体效果可以忽略不计
这时候去确认异常对象占总内存的占比,选择占比大的对象去处理,能事半功倍。
这里推荐比较成熟的memray
,可以跟踪python、C库的对象分配和泄漏情况,这里举一个使用案例,具体将指令放入ChatGPT
了解
memray attach \-o /app/memray.bin \--trace-python-allocators \--force \--follow-fork \--max-file-size 1GB \ # 限制文件大小-d 300 # 限制运行时间(秒)
异常对象泄漏原因
推荐objgraph.show_backrefs
展示对象泄漏引用链,具体看泄漏原因,一般是有未释放的引用或者复杂的循环引用导致。
找到异常引用链,释放对象时,解开相关引用即可。
对象释放情况确定与预防
对象释放情况确认
weakref.finalize
可注册销毁对象打印日志,确定对象销毁情况。
可通过弱引用来判定应该释放的对象是否还存在,且不影响对象引用计数和销毁。
对象泄露预防
现实中,复杂的引用关系链,解决一版后,后续很难保障添加的代码不再发生如此情况,可对主要的对象用弱引用简历全局监控,定时扫描打上卸载标记的对象,如果还在内存中,则报警。
后续再出一个Python内存泄漏 —— 微观篇,讲述如何操作