使用matplotlib和tkinter增加内存

时间:2018-12-06 17:01:35

标签: python-3.x matplotlib tkinter

问题:

我有一个tkinter窗口,其中带有matplotlib图,其中显示了一些行(是一个更大的程序的一部分)。我会定期添加新行,删除最旧的行以限制显示的行数。不幸的是,程序的大小不断增加。我已经在Windows和Linux上看到了这一点。

问题:

我应该如何编写一个长时间运行的图形框架以显示最后的n行,这些行不会耗尽我的全部内存?最好通过调整下面的代码,但是如果需要的话,我已经准备好进行完整的重写。

我已经删除了有问题的部分,并进行了一些测试。

关键呼叫似乎是canvas.draw()。即使未在图中添加任何行,所使用的内存也会随着时间逐渐增加。没有此调用,内存不会增加。当图中有更多行时,内存使用会更快增加。如果未创建轴(即没有fig.add_subplot(1, 1, 1)),则内存不会增加。

之前已经讨论了从matplotlib中删除行并回收内存(How to remove lines in a Matplotlib plot)。对要删除的行的weakref确认已将其删除,并且由于即使在未绘制任何行的情况下也存在问题stil,所以我怀疑这不是根本原因。

最接近的类似问题似乎是Declaration of FigureCanvasTkAgg causes memory leak,在该问题上调用绘图轴(而不是pyplot)解决了该问题。在这种情况下,这似乎并不适用-我没有使用pyplot进行绘图,如果直接在轴(ax.plot(x, y, '.-')上进行绘图,我仍然看到内存增加,并且再次出现时,我仍然看到问题没有画线。

使用mprof监视内存使用情况,并且我还使用Windows7上的系统诊断程序观看了它的发生。 mprof看到的内存使用示例:mprof plot of memory usage increasing

这是我目前得到的代码。与最初的用例相比,这已经大大减少了(_refresh_plot通常不会做任何事情,除非已将新数据从另一个线程添加到队列中,等等),但仍然显示出了问题。

import tkinter as tk
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import matplotlib as mpl
import weakref

class PlotFrame:
    def __init__(self, parent):
        self.fig = mpl.figure.Figure()
        self.canvas = FigureCanvasTkAgg(self.fig, master=parent)
        self.canvas.get_tk_widget().pack()
        self.ax = self.fig.add_subplot(1, 1, 1)
        self.ax.set_ylim((0, 150))
        self.ax.set_xlim((0, 12))

        self.counter = 0

        timer = self.fig.canvas.new_timer(interval=20)
        timer.add_callback(self._refresh_plot, ())
        timer.start()

    def _refresh_plot(self, arg):
        if True:  # True to plot 1 or more lines, False for no lines at all
            if len(self.ax.lines) > 2:  # Remove the oldest line
                existing_lines = self.ax.get_lines()
                # r = weakref.ref(existing_lines[0])  # weakref to check that the line is being correctly removed
                old_line = existing_lines.pop(0)
                old_line.remove()
                del old_line, existing_lines
                # print('Old line dead? {}'.format(r() is None))  # Prints Old line dead? True

            # Define a line to plot
            x = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
            y = [(v - abs(len(x) - self.counter % (2 * len(x)))) ** 2 for v in x]
            self.counter += 1

            new_line = mpl.lines.Line2D(x, y, linestyle='-', marker='.')
            self.ax.add_line(new_line)
            del new_line, x, y

        self.canvas.draw()

if __name__ == "__main__":
    root = tk.Tk()
    cpp = PlotFrame(root)
    root.mainloop()

长帖子的道歉。我一直在盯着这个眼睛已经很久了,以至于对我来说这可能是一个愚蠢的错误。

0 个答案:

没有答案