Tkinter定时绘图函数触发Out of memory错误,程序崩溃求助
内存泄漏问题排查与修复
你的代码运行一段时间后触发内存溢出,核心原因是每次调用plot时都重复创建新的Matplotlib绘图对象和Tkinter组件,旧对象未被彻底清理,导致内存堆积,以下是具体问题和修复方案:
核心问题点
- 每次销毁重建
plot_frame,并创建新的Figure、FigureCanvasTkAgg,旧对象的引用未被完全清除,持续占用内存 - 误用
plt.clf():你创建的是独立的self.fig,但plt.clf()操作的是Matplotlib全局的当前Figure,无法清理你自己创建的self.fig中的旧绘图元素 - 直接修改类属性
Simulation.ax:每次调用都会覆盖这个类级别的属性,旧的Axes对象因被类引用无法被垃圾回收 - 未主动清理旧
canvas:新创建self.canvas后,旧实例若仍被引用,会留在内存中无法释放
修复后的代码
def plot(self): # 复用plot_frame,无需每次销毁重建 if not hasattr(self, 'plot_frame') or self.plot_frame is None: self.plot_frame = tk.Frame(self, bg=self.bg) self.plot_frame.pack(fill="both", expand=True) # 复用Figure和Axes,避免重复创建新对象 if not hasattr(self, 'fig') or self.fig is None: self.fig = plt.Figure() self.ax = self.fig.add_subplot(111) self.ax.set_title("Damage Accumulation Curve") self.ax.set_xlabel("Load Case") self.ax.set_ylabel("Accumulative Fatigue Damage") # 初始化canvas并挂载到frame self.canvas = FigureCanvasTkAgg(self.fig, master=self.plot_frame) self.canvas.get_tk_widget().pack(fill="both", expand=True) else: # 清理当前Axes的旧绘图内容 self.ax.clear() # 重置标题和坐标轴标签(clear操作会清除这些配置) self.ax.set_title("Damage Accumulation Curve") self.ax.set_xlabel("Load Case") self.ax.set_ylabel("Accumulative Fatigue Damage") # 简化数据处理逻辑(原代码中重复切片无意义) x_axis = np.arange(0, len(Simulation.accumulated)) x = x_axis[-10:] y = np.array(Simulation.accumulated[-10:]) # 在复用的Axes上绘制新数据 self.ax.plot(x, y) # 更新canvas显示 self.canvas.draw() # 更新控件值 self.graph_theta.set(Simulation.theta) self.graph_arcl.set(Simulation.arcl) # 继续定时调用 self.after(30000, self.plot)
额外优化建议
- 避免修改类属性
Simulation.ax:如果Simulation是实例,改用实例属性(如sim_instance.ax);若必须用类属性,赋值前先执行del Simulation.ax解除旧对象引用 - 手动触发垃圾回收:在绘图完成后添加
import gc; gc.collect(),帮助及时释放无引用的对象 - 控制
Simulation.accumulated大小:如果这个列表持续增长,会占用大量内存,建议定期清理历史数据(比如只保留最近100个数据点)
内容的提问来源于stack exchange,提问作者user1821998
相关产品推荐
相关产品推荐

