matplotlib FigureCanvasTkAgg call creates memory leak

Viewed 100

python 3.10.4

While using matplotlib 3.5.1 I have encountered a problem in calling multiple times the function FigureCanvasTkAgg().

I have created this dummy python script to show the memory leak.

from tkinter import *
from matplotlib.figure import Figure
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import tracemalloc
import gc


def repeat(n, fig, root):
    for i in range(n):
        agg = FigureCanvasTkAgg(fig, root).get_tk_widget()
        agg.destroy()
        del agg
        gc.collect()


def main():
    root = Tk()
    root.geometry("300x300+0+0")
    fig = Figure(dpi=200)

    tracemalloc.start()
    tracemalloc.clear_traces()

    print(tracemalloc.get_traced_memory())
    repeat(10, fig, root)
    print(tracemalloc.get_traced_memory())

    tracemalloc.clear_traces()
    print(tracemalloc.get_traced_memory())

    repeat(20, fig, root)
    print(tracemalloc.get_traced_memory())

    tracemalloc.clear_traces()
    print(tracemalloc.get_traced_memory())

    repeat(30, fig, root)
    print(tracemalloc.get_traced_memory())

    tracemalloc.clear_traces()
    print(tracemalloc.get_traced_memory())

    root.mainloop()


if __name__ == "__main__":
    main()

I encountered this while trying to associate a FigureCanvasTkAgg object to some dynamic frames(Frame() objects which are created and destroyed by pressing some buttons).

Is there a way to fix it or to work around it?

1 Answers

I encountered this with my program. I create a flag which contains the FigureCanvasTkAgg and then add in a function when replotting that checks if that flag exists and destroy's it if it does.

In the function that creates the plot I capture the canvas widget just after its made:

# get plot exists for clearing
self.plot_figure_fileplot_exists = self.canvas_plot_figure_main.get_tk_widget()

and then prior to replotting, I run the below function:

def func_fileplot_clear(self):
    '''Clear the fileplot'''
    # destroy if previously drawn.
    if self.plot_figure_fileplot_exists:
        self.plot_figure_fileplot_exists.destroy()
Related