Jupyter Notebook中Python垃圾回收失效致内存耗尽问题求助
Jupyter Notebook内存无法释放?这些坑你肯定踩了!
嘿,这种Jupyter里内存越堆越多、gc完全不管用的情况我真的踩过好多次坑!你写的代码逻辑上没问题,但Jupyter的运行环境有几个容易被忽略的点,会导致垃圾回收器没法正常释放内存,我给你捋捋可能的原因和对应的解决办法:
Jupyter自动保存的输出在偷偷占内存
Jupyter会自动把每个单元格的执行结果存在Out[]字典里,哪怕你没把结果赋值给变量——比如thing.do_something()的输出,可能被悄悄存在Out[X]里,形成对thing的隐藏引用。
解决办法:- 在单元格末尾加
;,阻止Jupyter保存输出:result = thing.do_something(...); - 手动清理所有
Out开头的变量:for key in list(globals().keys()): if key.startswith('Out'): del globals()[key]
- 在单元格末尾加
对象有隐藏引用或循环引用,甚至是C层内存
有些第三方库的对象(比如numpy数组、pandas DataFrame)底层是C实现的内存,Python的gc管不到这些;还有些对象内部有循环引用,或者被某个全局变量、闭包悄悄引用了,导致gc没法标记回收。
解决办法:- 先调用对象自身的释放方法:如果
Thing类有.close()、.free()这类方法,一定要先调用再置为None - 用内存分析工具排查:比如
pympler可以帮你找出内存里的所有对象,看看谁在占着内存:from pympler import muppy, summary all_objects = muppy.get_objects() summary.print_(summary.summarize(all_objects))
- 先调用对象自身的释放方法:如果
result变量可能还在引用thing的内容
如果thing.do_something()返回的结果是thing内部属性的引用(比如返回了self.some_large_data),那哪怕你把thing置为None,result还拿着这个引用,内存照样释放不了。
解决办法:把result也置为None,再执行gc回收。内核残留太多垃圾,干脆重启
如果上面的方法都不管用,大概率是内核运行太久,各种残留引用堆成了乱麻,gc已经无力回天。这时候最简单的办法就是重启Jupyter内核——虽然麻烦,但能一次性清空所有内存。
最后给你一个优化后的示例代码,把这些点都考虑进去:
import gc from pympler import summary, muppy # 可选,用于内存排查 # 初始化对象并执行操作 thing = Thing() result = thing.do_something(...) # 末尾加;可阻止Jupyter保存输出 # 优先释放对象自身资源(如果有) if hasattr(thing, 'close'): thing.close() # 置空所有相关变量 thing = None result = None # 清理Jupyter的输出引用 for key in list(globals().keys()): if key.startswith('Out'): del globals()[key] # 强制触发垃圾回收 gc.collect() # 可选:查看当前内存占用情况,确认是否释放成功 all_objs = muppy.get_objects() summary.print_(summary.summarize(all_objs))
内容的提问来源于stack exchange,提问作者bkoodaa




