我有一个数据分析模块,其中包含调用matplotlib.pyplot
API多次生成每个运行中最多30个图形的函数。这些图形在生成后立即写入磁盘,因此需要从内存中清除。
目前,在我的每个函数结束时,我会执行以下操作:
import matplotlib.pyplot as plt
plt.clf()
不过,我不太确定这个语句是否真的可以清除内存。特别是因为我发现每次运行我的模块进行调试时,我的可用内存空间都在减少。
我需要怎么做才能确保每次将图形写入磁盘后真正清除内存?
我有一个数据分析模块,其中包含调用matplotlib.pyplot
API多次生成每个运行中最多30个图形的函数。这些图形在生成后立即写入磁盘,因此需要从内存中清除。
目前,在我的每个函数结束时,我会执行以下操作:
import matplotlib.pyplot as plt
plt.clf()
不过,我不太确定这个语句是否真的可以清除内存。特别是因为我发现每次运行我的模块进行调试时,我的可用内存空间都在减少。
我需要怎么做才能确保每次将图形写入磁盘后真正清除内存?
经过一周的试验,我找到了解决方案!希望它能帮到你。我的演示文稿已附上。
import matplotlib.pyplot as plt
import numpy as np
A = np.arange(1,5)
B = A**2
cnt=0
while(1):
cnt = cnt+1
print("########### test %d ###########" % cnt)
# here is the trick:
# set the figure a 'num' to prevent from re-malloc of a figure in the next loop
# and set "clear=True" to make the figure clear
# I never use plt.close() to kill the figure, because I found it doesn't work.
# Only one figure is allocated, which can be self-released when the program quits.
# Before: 6000 times calling of plt.figure() ~ about 1.6GB of memory leak
# Now: the memory keeps in a stable level
fig = plt.figure(num=1, clear=True)
ax = fig.add_subplot()
# alternatively use an other function in one line
# fig, ax = plt.subplots(num=1,clear=True)
ax.plot(A,B)
ax.plot(B,A)
# Here add the functions you need
# plt.show()
fig.savefig('%d.png' % cnt)
from matplotlib import pyplot as plt
f = plt.figure()
f.clear()
plt.close(f)
无论如何,您必须结合使用plt.clear()和plt.close()
更新(2021/01/21)
如果您正在使用MacOS系统以及其默认的后端(称为“MacOSX”),则这不起作用(至少在Big Sur中)。我发现的唯一解决方案是切换到其他众所周知的后端,例如TkAgg、Cairo等。要执行此操作,请键入:
import matplotlib
matplotlib.use('TkAgg') # Your favorite interactive or non-interactive backend
gc
模块来强制垃圾回收器在关闭、清除和标记为del
之后进行第二代垃圾收集,成功地解决了这个问题。 - probinsoplt.close(fig)
fig.clf()
gc.collect()
%reset_selective -f fig
我的一个小技巧可以帮助解决这个问题,不需要每次创建新的图形,只需将相同的fig对象传递给函数即可。
例如使用:
fig = plt.figure()
for i in range(100):
plt.plot(x,y)
替代,
for i in range(100):
fig = plt.figure()
plt.plot(x,y)
这更像是一个测试套件,而不是对问题的答案。 在此,我展示了截至2021年12月,没有提供的解决方案可以真正清空内存。
我们需要以下库:
import os
import psutil
import numpy
import matplotlib
import matplotlib.pyplot
def MatplotlibClearMemory():
#usedbackend = matplotlib.get_backend()
#matplotlib.use('Cairo')
allfignums = matplotlib.pyplot.get_fignums()
for i in allfignums:
fig = matplotlib.pyplot.figure(i)
fig.clear()
matplotlib.pyplot.close( fig )
#matplotlib.use(usedbackend)
我编写了一个脚本,创建了100个图形对象,然后尝试从内存中删除它们:
#Use TkAgg backend because it works better for some reason:
matplotlib.use('TkAgg')
#Create fake data for our figures:
x = numpy.arange(1000)
#Get system process information for printing memory usage:
process = psutil.Process(os.getpid())
#Check memory usage before we create figures:
print('BeforeFigures: ', process.memory_info().rss) # in bytes
#Make 100 figures, and check memory usage:
for n in range(100):
matplotlib.pyplot.figure()
matplotlib.pyplot.plot(x, x)
print('AfterFigures: ', process.memory_info().rss) # in bytes
#Clear the all the figures and check memory usage:
MatplotlibClearMemory( )
print('AfterDeletion: ', process.memory_info().rss) # in bytes
输出内存剩余情况:
>>> BeforeFigures: 76083200
>>> AfterFigures: 556888064
>>> AfterDeletion: 335499264
分配的内存不足一半被清除(如果使用标准后端,则清除的更少)。此堆栈溢出页面上唯一有效的解决方案是避免同时将多个图像放入内存中。
很遗憾,目前没有解决方案:
请参见:https://github.com/matplotlib/matplotlib/issues/20300
只有在使用GUI后端、创建新图形但不显示它们时才会出现此问题。这种用法是不合理的。对于所有相关场景,都有可行的用法模式。
plt.close("all")
,它按预期工作。import matplotlib.pyplot as plt
import copy
try:
# if script it run multiple times, only redefine once
plt.old_figure
except:
# matplotlib is imported for the first time --> redefine
plt.old_figure = copy.deepcopy(plt.figure)
def newfig(*args):
plt.show()
plt.close("all")
return plt.old_figure(*args)
plt.figure = newfig
我很清楚这不是一个好的解决方案,但它很简单、快速,并且对我起了作用!也许有一种方法可以装饰plt.figure而不是重新定义它。
plt.close("all")
吗?我有一个脚本,每个迭代会创建约60个图表,每个图表有3个轴。我在每个迭代的末尾使用它。内存消耗似乎正常。 - WGS