我有一个应用程序,通过单击按钮从中打开一个无模式子窗口。这个子窗口包含一个嵌入的matplotlib图。在关闭之后,我希望这个子窗口与matplotlib图一起被销毁。
问题是,即使在Qt端似乎正确删除了子窗口,似乎没有从该进程中释放内存。问题似乎是累积的,即如果我打开多个子窗口然后用'X'手动关闭它们,我的应用程序占用的内存会增加。
我的系统: Ubuntu 15.04 + Matplotlib 1.4.2 + python 2.7.9或3.4.3 + PySide 1.2.2
注意:我目前通过不破坏子窗口并重复使用相同的艺术家用新数据更新图形来避免“内存泄漏”问题。但是,我希望能够在不需要时完全释放这个子窗口占用的内存。
我尝试了gc.collect()
,setParent(None)
,deleteLater()
,del
,set_attributes(QtCore.Qt.WA_DeleteOnClose)
所能想到的所有组合,我试过要小心使用命名空间,并且只使用matplotlib艺术家的弱链接,我也试过使用和不使用pyplot
,但没有真正成功...我已经能够释放一些内存由matplotlib子窗口通过重新实现子窗口类的closeEvent
方法并手动清理东西来获取,但是,它仍然不能完美,并且它不漂亮。
下面是一个MCVE,它说明了迄今为止我所拥有的最佳“解决方案”的基本实现问题。我尝试了相同的代码,将FigureCanvasQTAgg
窗口小部件替换为“纯”qt窗口小部件(托管大QLabel
的{{1}})以及子窗口占用的所有内存( s)在结束时被释放。
QPixmap
这是我在尝试隔离问题时生成的一个简单应用程序。单击“显示图”按钮时:
我还添加了一个按钮来显式调用import sys
import numpy as np
from PySide import QtGui, QtCore
import matplotlib as mpl
mpl.rcParams['backend.qt4']='PySide'
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg
import gc
class MyApp(QtGui.QWidget):
def __init__(self):
super(MyApp, self).__init__()
btn_open = QtGui.QPushButton('Show Figure')
btn_open.clicked.connect(self.show_a_figure)
layout = QtGui.QGridLayout()
layout.addWidget(btn_open, 0, 0)
self.setLayout(layout)
def show_a_figure(self):
MyFigureManager(self).show()
class MyFigureManager(QtGui.QWidget):
def __init__(self, parent=None):
super(MyFigureManager, self).__init__(parent)
self.setWindowFlags(QtCore.Qt.Window)
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
layout = QtGui.QGridLayout()
layout.addWidget(MyFigureCanvas(), 0, 0)
self.setLayout(layout)
def closeEvent(self, event):
fig_canvas = self.findChild(MyFigureCanvas)
fig_canvas.figure.clear()
del fig_canvas.figure
fig_canvas.renderer.clear()
del fig_canvas.renderer
fig_canvas.mpl_disconnect(fig_canvas.scroll_pick_id)
fig_canvas.mpl_disconnect(fig_canvas.button_pick_id)
fig_canvas.close()
del fig_canvas
gc.collect()
super(MyFigureManager, self).closeEvent(event)
class MyFigureCanvas(FigureCanvasQTAgg):
def __init__(self, parent=None):
super(MyFigureCanvas, self).__init__(figure=mpl.figure.Figure())
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
#-- plot some data --
ax = self.figure.add_axes([0.1, 0.1, 0.85, 0.85])
ax.axis([0, 1, 0, 1])
N = 100000
x = np.random.rand(N)
y = np.random.rand(N)
colors = np.random.rand(N)
area = np.pi * (5 * np.random.rand(N)) ** 2
ax.scatter(x, y, s=area, c=colors, alpha=0.5)
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
w = MyApp()
w.show()
sys.exit(app.exec_())
。在第一种情况下(mode = 1),子窗口占用的所有内存在关闭时恢复。在“matplotlib模式”(mode = 2)中,可以在明确强制gc.collect()
时恢复某些内存,但有些内存不是。未释放的内存量似乎与mpl中绘制的点数量成比例,并且与同时打开的子窗口量有些相关。
我对内存管理知之甚少。我目前正通过Ubuntu中的System Load Indicator监控应用程序使用的内存。如果我做错了,请评论。
gc.collect()
SO帖子:
Matplotlib文档: