-
-
Notifications
You must be signed in to change notification settings - Fork 8k
Description
Bug summary
When creating, plotting to, and closing a figure in a scope (I tested with this in a function called in a loop), the memory usage steadily increases, sometimes by several megabytes for even simple calls to imshow.
(p.s. in the code below, the generate_frame function gets called 3 times to "warm up" the Python interpreter, just in case. same results with or without those lines, though)
Code for reproduction
import gc
import numpy as np
import os
import psutil
import matplotlib
import matplotlib.pyplot as plt
matplotlib.use('Agg')
def generate_frame(frame_idx: int):
plt.style.use("dark_background")
fig, axes = plt.subplots(2, 3, figsize=(16, 8))
axes = axes.flatten()
for i in range(6):
data = np.random.rand(1_000, 2_000)
axes[i].imshow(data)
plt.savefig("test.png", dpi=400, bbox_inches='tight', pad_inches=0.1)
plt.clf()
plt.close('all')
del fig
gc.collect()
return None
def get_memory():
return psutil.Process(os.getpid()).memory_info().rss / (1024**2)
for _ in range(3):
generate_frame(-1)
prev = get_memory()
for i in range(0, 20):
generate_frame(i)
current = get_memory()
print(f"Generated frame {i + 1}. Delta: {current - prev:.4f} MB of memory.")
prev = current
Actual outcome
Generated frame 1. Delta: 4.1602 MB of memory.
Generated frame 2. Delta: 12.0195 MB of memory.
Generated frame 3. Delta: 0.2266 MB of memory.
Generated frame 4. Delta: 0.0859 MB of memory.
Generated frame 5. Delta: 4.1641 MB of memory.
Generated frame 6. Delta: 4.1758 MB of memory.
Generated frame 7. Delta: 0.0781 MB of memory.
Generated frame 8. Delta: 0.0430 MB of memory.
Generated frame 9. Delta: 0.0156 MB of memory.
Generated frame 10. Delta: 0.0117 MB of memory.
Generated frame 11. Delta: 0.1289 MB of memory.
Generated frame 12. Delta: 0.0117 MB of memory.
Generated frame 13. Delta: 0.3750 MB of memory.
Generated frame 14. Delta: 4.0859 MB of memory.
Generated frame 15. Delta: 4.1172 MB of memory.
Generated frame 16. Delta: 0.0234 MB of memory.
Generated frame 17. Delta: 0.0195 MB of memory.
Generated frame 18. Delta: 0.0195 MB of memory.
Generated frame 19. Delta: 0.0234 MB of memory.
Generated frame 20. Delta: 0.0234 MB of memory.
Expected outcome
Using the same code but with no reference to matplotlib, gives:
Generated frame 1. Delta: 4.0000 B of memory.
Generated frame 2. Delta: 12.0000 B of memory.
Generated frame 3. Delta: 176.0000 B of memory.
Generated frame 4. Delta: 504.0000 B of memory.
Generated frame 5. Delta: 164.0000 B of memory.
Generated frame 6. Delta: 0.0000 B of memory.
Generated frame 7. Delta: 160.0000 B of memory.
Generated frame 8. Delta: 0.0000 B of memory.
Generated frame 9. Delta: 28.0000 B of memory.
Generated frame 10. Delta: 16.0000 B of memory.
Generated frame 11. Delta: 0.0000 B of memory.
Generated frame 12. Delta: 24.0000 B of memory.
Generated frame 13. Delta: 24.0000 B of memory.
Generated frame 14. Delta: 0.0000 B of memory.
Generated frame 15. Delta: 0.0000 B of memory.
Generated frame 16. Delta: 0.0000 B of memory.
Generated frame 17. Delta: 0.0000 B of memory.
Generated frame 18. Delta: 0.0000 B of memory.
Generated frame 19. Delta: 0.0000 B of memory.
Generated frame 20. Delta: 0.0000 B of memory.
Code for that output:
import gc
import numpy as np
import os
import psutil
def generate_frame(frame_idx: int):
for i in range(6):
data = np.random.rand(100, 200)
gc.collect()
return None
def get_memory():
return psutil.Process(os.getpid()).memory_info().rss / (1024)
for _ in range(3):
generate_frame(-1)
prev = get_memory()
for i in range(0, 20):
generate_frame(i)
current = get_memory()
print(f"Generated frame {i + 1}. Delta: {current - prev:.4f} B of memory.")
prev = current
In other words, matplotlib should properly clean up references/resources to not generate a consistent upward trend in memory usage.
Additional information
In my real use-case, code very similar to this (but with colorbars. additional axes, etc.), using larger data, generates nearly 0.2 GB per frame as a consistent trend. I'm pretty sure the issue comes from matplotlib, as demonstrated with the example above.
Operating system
MacOS
Matplotlib Version
3.10.3
Matplotlib Backend
Agg
Python version
3.12.10
Jupyter version
N/A
Installation
pip