在PyQt GUI中嵌入和更新matplotlib图时内存泄漏

时间:2015-04-21 08:04:52

标签: python python-3.x matplotlib

我正在尝试嵌入一个matplotlib图,它每秒都会更新到PyQt GUI主窗口。

在我的程序中,我使用threading.Timer通过下面显示的timer函数每秒调用一次更新函数。我有一个问题:我的程序每秒都会变大 - 每4秒钟大约1k。我最初的想法是append函数(在update_figure中返回一个新数组)不会删除旧数组?这可能是我问题的原因吗?

def update_figure(self):
    self.yAxis = np.append(self.yAxis, (getCO22()))
    self.xAxis = np.append(self.xAxis, self.i)
    # print(self.xAxis)
    if len(self.yAxis) > 10:
        self.yAxis = np.delete(self.yAxis, 0)

    if len(self.xAxis) > 10:
        self.xAxis = np.delete(self.xAxis, 0)

    self.axes.plot(self.xAxis, self.yAxis, scaley=False)
    self.axes.grid(True)

    self.i = self.i + 1

    self.draw()

这是我的计时器功能 - 这是通过点击我的PyQt GUI中的按钮触发,然后调用自己,如你所见:

def timer(self):
    getCH4()
    getCO2()
    getConnectedDevices()
    self.dc.update_figure()
    t = threading.Timer(1.0, self.timer)
    t.start()

编辑: 我无法发布我的整个代码,因为它需要大量的.dll包含。所以我会尝试解释这个程序的作用。

在我的GUI中,我希望随着时间的推移显示我的CO 2 值。我的get_co22函数只返回一个浮点值,我100%确定这个工作正常。使用我的计时器,如上所示,我想继续为matplotlib图添加一个值 - Axes对象可以作为self.axes使用。我尝试绘制数据的最后10个值。

编辑2: 在一些discussion in chat之后,我尝试在update_figure()循环中调用while并使用一个线程来调用它,并能够创建这个最小的例子http://pastebin.com/RXya6Zah。这改变了代码的结构,以便将update_figure()调用到以下内容:

def task(self):
    while True:
        ui.dc.update_figure()
        time.sleep(1.0)

def timer(self):
    t = Timer(1.0, self.task())
    t.start()

但现在程序在5次迭代后崩溃。

2 个答案:

答案 0 :(得分:2)

问题绝对不在于如何附加到numpy数组或截断它。

这里的问题在于您的线程模型。将计算循环与GUI控制循环集成起来很困难。

从根本上说,您需要使用GUI线程来控制何时调用更新代码(如果需要,生成一个新线程来处理它) - 这样

  1. 您的代码不会阻止GUI更新,
  2. GUI更新不会阻止您的代码执行和
  3. 你不会产生大量持有多个对象副本的线程(这可能是你的内存泄漏的来源)。
  4. 在这种情况下,由于您的主窗口由PyQt4控制,您想使用QTimer(请参阅simple example here

    所以 - 将您的timer代码改为

    def task(self):
        getCH4()
        getCO2()
        getConnectedDevices()
        self.dc.update_figure()
    
    def timer(self):
        self.t = QtCore.QTimer()
        self.t.timeout.connect(self.task)
        self.t.start(1000)
    

    这应该有效。保持对QTimer的引用至关重要 - 因此self.t = QtCore.QTimer()而不是t = QtCore.QTimer(),否则QTimer对象将被垃圾收集。

    注意:

    这是long thread in chat的摘要,澄清了问题,并通过几种可能的解决方案。特别是 - OP在这里设法模拟了一个更简单的可运行示例:http://pastebin.com/RXya6Zah

    并且完整的可运行示例的固定版本位于:http://pastebin.com/gv7Cmapr

    相关的代码和解释如上所述,但链接可能会帮助任何想要复制/解决问题的人。请注意,它们需要安装PyQt4

答案 1 :(得分:0)

如果你每次创建一个新的数字这很常见。

matplotlib不会释放你创建的数字,除非你问它,有些想法:

pylab.close() 

请参阅How can I release memory after creating matplotlib figures