You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

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置为Noneresult还拿着这个引用,内存照样释放不了。
    解决办法:把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

火山引擎 最新活动