含全局变量的Python循环脚本内存持续增长问题排查
问题根源
你遇到的内存泄漏问题,核心原因在于**go.FigureWidget的设计特性**:它是为Jupyter交互式环境开发的组件,内部会持有额外的资源(比如事件监听、ipywidgets关联的底层引用),这些资源不会被Python的自动垃圾回收机制完全清理——哪怕你删除了对figs_all的引用,旧的FigureWidget实例仍可能残留未释放的内存。
解决方案
针对你的场景,最彻底的解决办法是替换组件类型,或者手动清理资源,具体如下:
1. 改用普通go.Figure(推荐)
Dash应用本身自带交互回调能力,完全不需要依赖FigureWidget的交互式特性。直接替换为普通go.Figure,可以彻底避免额外资源绑定导致的内存泄漏:
import sys import time import gc import numpy as np import plotly.graph_objects as go def load_data(): global figs_all Npts = 100000 Nplots = 100 Nsubplots = 5 # 先清理旧变量引用 if 'figs_all' in globals(): del figs_all figs_all = {} for ii in range(0,Nplots): title = str(ii) print(title) # 替换为普通go.Figure fig = go.Figure(layout={'width': 1600, 'height': 800}) for jj in range(0,Nsubplots): xx = np.random.rand(Npts) yy = np.random.rand(Npts) fig.add_scattergl(x=xx, y=yy, mode='markers', name=title) figs_all[title] = fig # 手动触发垃圾回收,加速内存释放 gc.collect() if __name__ == '__main__': load_data() while 1: time.sleep(1) load_data()
2. 若必须保留FigureWidget,手动清理资源
如果你的场景确实需要FigureWidget,则需要在替换全局变量前,主动调用每个实例的close()方法,释放其持有的底层资源:
def load_data(): global figs_all # 先清理旧的FigureWidget资源 if 'figs_all' in globals() and figs_all is not None: for fig in figs_all.values(): fig.close() # 释放FigureWidget的关联资源 del figs_all Npts = 100000 Nplots = 100 Nsubplots = 5 figs_all = {} for ii in range(0,Nplots): title = str(ii) print(title) fig = go.FigureWidget(layout={'width': 1600, 'height': 800}) for jj in range(0,Nsubplots): xx = np.random.rand(Npts) yy = np.random.rand(Npts) fig.add_scattergl(x=xx, y=yy, mode='markers', name=title) figs_all[title] = fig gc.collect()
补充说明
- 内存不会立刻回落到初始值是正常现象:Python的垃圾回收有延迟,numpy数组的内存管理也有自身机制,但修改后内存不会再持续攀升。
- 你的Dash重启逻辑可以保留:结合上述修改后,每次重启前的内存泄漏问题会被解决。
内容的提问来源于stack exchange,提问作者ksoth
相关产品推荐
相关产品推荐

