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

Row*_*iek 5 python matplotlib python-3.x

我试图嵌入一个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()
Run Code Online (Sandbox Code Playgroud)

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

def timer(self):
    getCH4()
    getCO2()
    getConnectedDevices()
    self.dc.update_figure()
    t = threading.Timer(1.0, self.timer)
    t.start()
Run Code Online (Sandbox Code Playgroud)

编辑:我无法发布我的整个代码,因为它需要很多.dll包含.所以我将尝试解释这个程序的功能.

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

编辑2:在聊天中进行了一些讨论后,我尝试将调用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()
Run Code Online (Sandbox Code Playgroud)

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

J R*_*ape 2

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

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

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

  1. 您的代码不会阻止 GUI 更新,
  2. GUI 更新不会阻止您的代码执行
  3. 您不会产生大量持有对象多个副本的线程(这可能是内存泄漏的来源)。

在这种情况下,由于您的主窗口是由PyQt4控制的,因此您需要使用QTimer(请参阅此处的简单示例

所以 - 将您的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)
Run Code Online (Sandbox Code Playgroud)

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


笔记:

这是聊天中一个长线程的总结,澄清了问题并研究了几种可能的解决方案。特别是 - OP 设法在这里模拟了一个更简单的可运行示例: http: //pastebin.com/RXya6Zah

完整可运行示例的固定版本在这里: http: //pastebin.com/gv7Cmapr

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