重启包含Matplotlib画布的PyQt QApplication时崩溃如何解决?
问题根因
- 调用
QApplication.exit()只会终止Qt事件循环,不会自动销毁已经创建的主窗口、Matplotlib画布等对象,资源会残留在内存中 - Matplotlib的Qt5Agg后端会全局持有画布的引用,第二次初始化QApplication实例时,旧的残留资源和新实例会发生冲突,直接触发崩溃
- 仅调用
self.sc.close_event()无法完全释放Matplotlib关联资源,也没有处理主窗口的销毁逻辑,残留问题没有解决
修复方案
调整退出逻辑和主循环的资源回收逻辑即可解决,修改后的完整代码如下:
import sys import gc import matplotlib matplotlib.use('Qt5Agg') from PyQt5 import QtCore, QtGui, QtWidgets from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg, NavigationToolbar2QT as NavigationToolbar from matplotlib.figure import Figure class MplCanvas(FigureCanvasQTAgg): def __init__(self, parent=None, width=5, height=4, dpi=100): fig = Figure(figsize=(width, height), dpi=dpi) self.axes = fig.add_subplot(111) super(MplCanvas, self).__init__(fig) class MainWindow(QtWidgets.QMainWindow): REBOOT_CODE = -654321 def __init__(self, *args, **kwargs): super(MainWindow, self).__init__(*args, **kwargs) self.sc = MplCanvas(self, width=5, height=4, dpi=100) self.sc.axes.plot([0, 1, 2, 3, 4], [10, 1, 20, 3, 40]) button = QtWidgets.QPushButton('reload', self) button.clicked.connect(lambda: self.reloadapp()) layout = QtWidgets.QVBoxLayout() layout.addWidget(button) layout.addWidget(self.sc) widget = QtWidgets.QWidget() widget.setLayout(layout) self.setCentralWidget(widget) def reloadapp(self): self.sc.close_event() # 主动销毁主窗口,释放所有Qt控件资源 self.close() # 释放Matplotlib画布关联的figure资源,清除后端全局引用 del self.sc.figure QtWidgets.QApplication.exit(MainWindow.REBOOT_CODE) if __name__ == '__main__': exit_code = MainWindow.REBOOT_CODE while exit_code == MainWindow.REBOOT_CODE: app = QtWidgets.QApplication(sys.argv) w = MainWindow() w.show() exit_code = app.exec_() # 手动删除窗口和应用实例 del w del app # 强制垃圾回收,清理所有残留的未释放资源 gc.collect()
核心改动点:
- 退出前先调用
self.close()销毁主窗口,释放所有Qt控件占用的资源 - 删除Matplotlib画布关联的figure对象,清除后端全局持有的引用
- 事件循环结束后手动删除窗口和应用实例,配合垃圾回收保证所有残留资源被清理
内容的提问来源于stack exchange,提问作者Maracman
相关产品推荐
相关产品推荐

