3

I'm having difficulty figuring out just why the declaration of FigureCanvasTkAgg causes a memory leak, I have the following lines in my class __init__ method:

   # pndwinBottom is a paned window of the main screen
   self.__drawplotFrame = Frame(pndwinBottom, width=WIDTH, height=HEIGHT)                                 # the frame on which we will add our canvas for drawing etc.

   self.__fig = plt.figure(figsize=(16,11))
   self.__drawplotCanvas = FigureCanvasTkAgg(self.__fig, master=self.__drawplotFrame)

the problem is that upon running my application , and exiting, python32.exe remains in my process window and will clog up my computer. Commenting out these three lines however will allow my application to exit and the process will correctly terminate. What could these lines be doing to my application that prevents the process from ending after the application is finished? Thanks

edit


The memory leak seems to be caused by only the line self.__fig = plt.figure(figsize=(16, 11)) . Do I need to do some sort of deconstruction with plt before exiting?

Syntactic Fructose
  • 18,936
  • 23
  • 91
  • 177

2 Answers2

3

I was having this problem with memory leak, and I think I found a solution. In my __init__ method I was creating a frame, and then passing it to a plotting function to do the actual work. In that function, I would create a new matplotlib.figure.Figure instance, which for some reason was not destroyed when the function went out of scope.

To solve it, i did this: in the __init__ method, I created not only the frame but also the figure (complete with axes) and canvas:

    results = tk.Frame(self)
    f = Figure()
    ax0 = f.add_subplot(211)
    ax1 = f.add_subplot(212)
    self.canvas = FigureCanvasTkAgg(f, results)
    self.canvas.get_tk_widget().pack(expand=True, fill='both')

Then, inside the plotting method,

    ax0, ax1 = self.canvas.figure.get_axes()
    ax0.clear()
    ax0.plot(x, y)

    ax1.clear()
    ax1.plot(x, z)

    self.canvas.draw()

And just like that, the leak disappeared!

  • This solved a very similar problem I was having in python3.8 with FigureCanvasTkAgg; it definitely appears that calling FigureCanvasTkAgg once and making and clearing the subplots as needed is the way to go! – JSK Oct 18 '21 at 19:17
1

I'm gonna guess this is caused by the pyplot figure not being destroyed when the Tkinter window is closed.
Like in the embedding in tk example try using Figure:

from matplotlib.figure import Figure

self.__fig = Figure(figsize=(16,11))

example use:

import Tkinter as tk
import matplotlib
matplotlib.use('TkAgg')

from matplotlib.figure import Figure
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg

class App():
    def __init__(self, parent):

        self.__drawplotFrame = tk.Frame(parent, width=500, height=500)
        self.__drawplotFrame.pack()

        self.__fig = Figure(figsize=(16,11))
        self.__p = self.__fig.add_subplot(1,1,1)
        self.__p.plot(range(10), range(10))

        self.__drawplotCanvas = FigureCanvasTkAgg(self.__fig, master=self.__drawplotFrame)
        self.__drawplotCanvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1)

root = tk.Tk()
App(root)
root.mainloop()
fhdrsdg
  • 10,297
  • 2
  • 41
  • 62
  • Thanks that seemed to do it, whats the difference between `pyplot.figure` and `matplotlib.figure` though and why was pyplot giving me the memory leak? **EDIT** actually, all seems to work until I end up plotting something to the figure, it then seems to stop the process cleanup once again – Syntactic Fructose Jun 08 '15 at 13:33
  • I don't really know more about the difference than what's in [this answer](http://stackoverflow.com/a/5450333/3714930). Regarding your edit, I'm plotting something in my example too, do you plot in the same way? Or does my example give you problems too? – fhdrsdg Jun 08 '15 at 13:54
  • I've remarked your answer as correct since you did in fact solve my issue, however I have yet another error which causes an additional memory leak. When calling the plot function, it now seems the line `im = plt.imshow(regrid_atten_back, cmap = cm, aspect = 'auto', norm = plot_norm, extent = extents, interpolation = None)` causes the program to not correctly free matplotlib. `plt` is pyplot in this case. This line is for showing a colorbar just to the right of the actual plot – Syntactic Fructose Jun 08 '15 at 13:55
  • Again, don't use pyplot. `self.__p.imshow(...)` should work with `self.__p` defined as in my example. – fhdrsdg Jun 08 '15 at 15:09