Matplotlib vs Tkinter:使用FigureCanvasTkAgg进行内存泄漏

时间:2017-03-29 15:06:43

标签: python python-2.7 matplotlib tkinter memory-leaks

我在下面的脚本中使用matplotlib和Tkinter遇到了内存泄漏问题。不久,这个脚本生成包含箭头的matplotlib图形,然后清理最终的旧图形并将这些图形嵌入到Tkinter框架的画布中。

问题是清洁步骤不起作用,并且在刷新图形时使用的内存无限增加。使用FigureCanvasTkAgg时,数字似乎不会被破坏,但如果它们未嵌入画布中则会被销毁。

是Mpl / Tk内部问题还是有办法解决这个问题?

以下是代码:

#! /usr/bin/python2.7
#-*- coding: utf-8 -*-
import matplotlib
matplotlib.use('Tkagg')
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import matplotlib.pyplot as plt
import matplotlib.patches as patches
from Tkinter import *
import gc
import resource
from matplotlib.figure import Figure

class Data(object):
    def __init__(self):
        self.list_fig = []
        self.list_list = [[1,2,3],[1,2,3],[1,2,3],[1,2,3]]
        self.list_wid = []

def Clean_Canvas(Test,frame):
    """ clean content of each canvas
    generated in print_figure """
    # try to eliminate each canevas contained in frame
    for i in Test.list_wid:
        i.grid_forget()
        i.destroy()
        del i
    # try to eliminate each figure in list_fig_g
    for j,i in enumerate(Test.list_fig):
        plt.close(i)
        i.clf()
        i.clear()
    Test.list_fig = []
    # get canvas ids of Tk frame
    Test.list_wid = frame.winfo_children()
    # try to eliminate nonref objects
    gc.collect()

def Figure_Maker(Test):
    """ generates 3 arrows in 4 matplotlib
    figures from list_list """
    compteur = 0
    for n,element in enumerate(Test.list_list):
        fig1 = Figure(figsize=(1,1))
        ax1 = fig1.add_subplot(111, aspect='equal',ylim=[-1,2],xlim=[-1,2])
        # drows arrows for each element in each element of list_list_g
        for k in Test.list_list[n]:
            ax1.add_patch(
                patches.Arrow(
                    0,            # x
                    -0,            # y
                    k,            # dx
                    0,            # dy
                    width=1,
                    facecolor="red",
                )
            )
        Test.list_fig.append(fig1)

def Print_Figures(Test,frame):
    """ print each plot of arrows in
    each canevas of frame"""
    compteur = 0
    # embed mpl figures in canvas
    for i in Test.list_fig:
        canvas = FigureCanvasTkAgg(i, master=frame)
        canvas.get_tk_widget().grid(row=compteur,column=1)
        compteur += 1
    # get ids of each canevas to eliminates them when refreshing (in Clean_figure)
    Test.list_wid = frame.winfo_children()

def Launcher(Test,frame):
    print 'Memory usage: %s (kb)' % resource.getrusage(resource.RUSAGE_SELF).ru_maxrss,
    Clean_Canvas(Test,frame)
    Figure_Maker(Test)
    Print_Figures(Test,frame)
    print 'Memory usage: %s (kb)' % resource.getrusage(resource.RUSAGE_SELF).ru_maxrss

# main Tk
Test_g = Data()
root = Tk()
root.wm_title("mem_test")
root.configure(background="#454545")
root.winfo_toplevel()
##### entete context
Entete5 = Label(root,text="plots", bg="#454545", width=20, height=1, bd=5, fg="white").grid(row=0,column=1)
############# déclaration des scrolling bar (stickyN+S = barre et non pas des fleches)
scrollbary = Scrollbar(root, orient=VERTICAL,bg="#454545")
scrollbary.grid(row=1,column=2, sticky=N+S, rowspan=14)
#scrollbary.rowconfigure(0, weight=4)
scrollbarx = Scrollbar(root, orient=HORIZONTAL,bg="#454545")
scrollbarx.grid(row=15,column=1, sticky=E+W)
############ creation d'un canvas qui va accueillir ma frame_g
fond = Canvas(root,yscrollcommand=scrollbary.set,xscrollcommand=scrollbarx.set, width=800, height=200,bg="white")
fond.grid(row=1, column=1, rowspan=14, sticky=N+S+E+W)
############ Mouswheel
root.bind('<4>', lambda event : fond.yview('scroll', -1, 'units'))
root.bind('<5>', lambda event : fond.yview('scroll', 1, 'units'))
############ attacheleent des scrollbar sur le canvas
scrollbary.config(command=fond.yview)
scrollbarx.config(command=fond.xview)
########### attachement du fond sur un frame_g
frame_g = Frame(fond,width=80, height=10)
frame_g.grid(row=0,column=1,sticky=N+E+W+S)
######### empecher le canvas de se resizer
fond.create_window(0, 0,  window=frame_g)
frame_g.update_idletasks()
fond.config(scrollregion=fond.bbox("all"))
list_wid = frame_g.winfo_children()
###### label des annotations
root.columnconfigure(2, pad=10)

######bouton selkection
Load = Button (root, text = "Load selection", command = lambda : Launcher(Test_g,frame_g), anchor=N)
Load.grid(row=7,column=4,sticky=N+E+W+S)
Load.config( height = 1, width = 11 )
root.mainloop()

这里是用于每次刷新的内存:

Memory usage: 39832 (kb) Memory usage: 45376 (kb)
Memory usage: 46168 (kb) Memory usage: 46960 (kb)
Memory usage: 47224 (kb) Memory usage: 47752 (kb)
Memory usage: 47752 (kb) Memory usage: 48544 (kb)
Memory usage: 48544 (kb) Memory usage: 48808 (kb)
Memory usage: 48808 (kb) Memory usage: 49072 (kb)
Memory usage: 49072 (kb) Memory usage: 49336 (kb)
Memory usage: 49336 (kb) Memory usage: 49864 (kb)
Memory usage: 49864 (kb) Memory usage: 50128 (kb)
Memory usage: 50128 (kb) Memory usage: 50392 (kb)
Memory usage: 50392 (kb) Memory usage: 50656 (kb)

(Python 2.7,MPL 1.1.1,Ubuntu 12.04)

谢谢,

PiSiGa

0 个答案:

没有答案