You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Memory leak in plt.close() when unshown figures in GUI backends are closed #20300
When creating multiple plots (e.g. in a loop), the allocated memory for the process increases in each iteration even though the figure is cleared each time.
This indeed slowly increases memory usage (checked with memory_profiler and 500 samples instead of 5000):
However, the code is not reasonable in itself. It seems you are trying wildly delete everything. But though that, fig.clf() cleans the figure, including it's axes, plt.cla() does nothing then, and the ax object continues to live detached from any figure so that the data from ax.plot will not show up in any figure.
While that doesn't explain the memory leak, let's try and start from a realistic example: What are you trying to do exactly? Do you only want to replace data inside the Axes? If so, the only cleanup command necessary should be ax.clear() (or historically synonym ax.cla()). If you need to wipe the whole figure, fig.clf() is the way to go (But I expect fig.close(); fig = plt.figure() should be similarly efficient).
I am aware that the example code contains redundant clear commands, I wanted to emphasize that I tried all the commands that solved past issues of a similar kind. However, after your remarks regarding a floating axis object I noticed that this might be partially the reason for the issue, and only the following combination of clear commands in each iteration is already enough to result in the memory growth problem:
plt.cla()
plt.close()
In my use case I only need to clear the axis data, therefore for me the issue would be solved by only using plt.cla() as you said. I unnecessarily went the way to rebuild the whole figure in each iteration at first, resulting in me using the above functions. Though I am still wondering why the code results in the memory leak. Is there no way to completely clean up a figure short of stopping the whole python process? Unfortunately I am not familiar enough with the inner workings of matplotlib.
As proposed in #5795, this has to do with created but not-shown GUI windows (all tests done with Qt on linux).
It works if you show the windows and close them afterwards
for i in range(500):
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot([0,1,2,3,4,5], [0,1,2,3,4,5])
plt.show(block=False)
plt.pause(0.2)
plt.close(fig)
The edges are probably due to garbage collection.
It works if you use a non-GUI backend
import matplotlib as mpl
mpl.use('agg')
import matplotlib.pyplot as plt
for i in range(500):
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot([0,1,2,3,4,5], [0,1,2,3,4,5])
plt.savefig(f'test{i:03d}.png')
plt.close(fig)
Summary
This only happens if you work in a GUI backend, create new figures, but don't show them. This way of usage is not reasonable. There are working usage patterns for all relevant scenarios.
I'm closing this as "won't fix" because the memory leak doesn't happen for proper usage, and I assume that debugging the GUI framework memory management would be quite hard.
changed the title [-]Memory leak in plt.close() if unshown figures in GUI backends are closed[/-][+]Memory leak in plt.close() when unshown figures in GUI backends are closed[/+]on May 25, 2021
gc + circular references is the source of the jagged edges, Python only does the more expensive sweeps every so often and we have a lot of circular references!
Activity
timhoffm commentedon May 25, 2021
This indeed slowly increases memory usage (checked with memory_profiler and 500 samples instead of 5000):
However, the code is not reasonable in itself. It seems you are trying wildly delete everything. But though that,
fig.clf()cleans the figure, including it's axes,plt.cla()does nothing then, and theaxobject continues to live detached from any figure so that the data fromax.plotwill not show up in any figure.While that doesn't explain the memory leak, let's try and start from a realistic example: What are you trying to do exactly? Do you only want to replace data inside the Axes? If so, the only cleanup command necessary should be
ax.clear()(or historically synonymax.cla()). If you need to wipe the whole figure,fig.clf()is the way to go (But I expectfig.close(); fig = plt.figure()should be similarly efficient).P-Takenaka commentedon May 25, 2021
I am aware that the example code contains redundant clear commands, I wanted to emphasize that I tried all the commands that solved past issues of a similar kind. However, after your remarks regarding a floating axis object I noticed that this might be partially the reason for the issue, and only the following combination of clear commands in each iteration is already enough to result in the memory growth problem:
In my use case I only need to clear the axis data, therefore for me the issue would be solved by only using
plt.cla()as you said. I unnecessarily went the way to rebuild the whole figure in each iteration at first, resulting in me using the above functions. Though I am still wondering why the code results in the memory leak. Is there no way to completely clean up a figure short of stopping the whole python process? Unfortunately I am not familiar enough with the inner workings of matplotlib.timhoffm commentedon May 25, 2021
Regular usage with clearing the Axes or figure does not have a memory leak. It seems that
plt.close()doesn't completely get rid of the data.Axes clearing
Figure clearing
Figure closing
Simple figure closing
Closing with garbage collection
Strips of some memory, but doesn't help with the leak. All this does is that the gc slows down execution:
jklymak commentedon May 25, 2021
I'm relatively sure tK leaking has been documented before. Does this happen for other backends?
timhoffm commentedon May 25, 2021
As proposed in #5795, this has to do with created but not-shown GUI windows (all tests done with Qt on linux).
It works if you show the windows and close them afterwards
The edges are probably due to garbage collection.
It works if you use a non-GUI backend
Summary
This only happens if you work in a GUI backend, create new figures, but don't show them. This way of usage is not reasonable. There are working usage patterns for all relevant scenarios.
I'm closing this as "won't fix" because the memory leak doesn't happen for proper usage, and I assume that debugging the GUI framework memory management would be quite hard.
[-]Memory not freed up correctly[/-][+]Memory leak in plt.close() if unshown figures in GUI backends are closed[/+][-]Memory leak in plt.close() if unshown figures in GUI backends are closed[/-][+]Memory leak in plt.close() when unshown figures in GUI backends are closed[/+]tacaswell commentedon May 27, 2021
gc + circular references is the source of the jagged edges, Python only does the more expensive sweeps every so often and we have a lot of circular references!
Fixed a problem where we were using teh wrong information for the spi…
Final round of improvements for this project
Final round of improvements for this project
Final round of improvements for this project
Final round of improvements for this project