如何完全清除所有matplotlib图形的内存

43

我有一个数据分析模块,其中包含调用matplotlib.pyplot API多次生成每个运行中最多30个图形的函数。这些图形在生成后立即写入磁盘,因此需要从内存中清除。

目前,在我的每个函数结束时,我会执行以下操作:

import matplotlib.pyplot as plt

plt.clf()

不过,我不太确定这个语句是否真的可以清除内存。特别是因为我发现每次运行我的模块进行调试时,我的可用内存空间都在减少。

我需要怎么做才能确保每次将图形写入磁盘后真正清除内存?


13
你尝试过使用plt.close("all")吗?我有一个脚本,每个迭代会创建约60个图表,每个图表有3个轴。我在每个迭代的末尾使用它。内存消耗似乎正常。 - WGS
2
谢谢你的回答!它起作用了!我还发现了这篇很棒的stackoverflow帖子https://dev59.com/E2sy5IYBdhLWcg3w8Slc,它回答了我的问题! - AKKO
这个回答解决了你的问题吗?如何在创建matplotlib图形后释放内存 - losnihciL
7个回答

35

经过一周的试验,我找到了解决方案!希望它能帮到你。我的演示文稿已附上。

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)

4
可以证实,效果非常好。但要注意,如果您在使用上述解决方案时结合 plt.close(f) 使用,则仍会出现内存泄漏问题。 - Guillermo J.
完美的解决方案!在我的代码中,我添加了“fig.clear()”和“plt.close(fig)”来保存图像后完全清除RAM。 - jared
谢谢。同意使用plt.close()是错误的做法。谢谢! - Ed Landau
经过许多令人困惑的尝试后,完全解决了我的问题 - 太棒了! - SteveZissou
num=1, clear=True 的效果非常完美。你真是个救命稻草。我有一些脚本为数百个地理位置创建了几十个图表,结果内存占用量达到了100GB。fig.clear 和 plt.close 对我来说都不起作用,但是在使用这个参数之后,脚本的运行仅占用1.5GB的内存,基本上只是实际数据集所占用的内存空间。 - matthewiannowlin

29
尤其是当您正在运行多个进程或线程时,最好定义您的图形变量并直接使用它:
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之后进行第二代垃圾收集,成功地解决了这个问题。 - probinso

6
我有一个数据分析模块,其中包含调用Matplotlib pyplot API的多个函数。
你能否编辑你的函数以调用matplotlib?我遇到了同样的问题,尝试了下面的命令,但都没有起作用。
plt.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)

5

这更像是一个测试套件,而不是对问题的答案。 在此,我展示了截至2021年12月,没有提供的解决方案可以真正清空内存。

我们需要以下库:

import os
import psutil 
import numpy
import matplotlib
import matplotlib.pyplot

我创建了一个函数, 应该可以清除所有 matplotlib 的内存:
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

分配的内存不足一半被清除(如果使用标准后端,则清除的更少)。此堆栈溢出页面上唯一有效的解决方案是避免同时将多个图像放入内存中。


随着我创建更多的图形或使它们保存更多的数据,这似乎渐近地接近清除一半的内存。 - D A

1

很遗憾,目前没有解决方案:

请参见:https://github.com/matplotlib/matplotlib/issues/20300

只有在使用GUI后端、创建新图形但不显示它们时才会出现此问题。这种用法是不合理的。对于所有相关场景,都有可行的用法模式。


这应该是被接受的答案!不仅没有解决方案,而且在matplotlib开发社区中有一致的意见,永远不会修复这个问题。 - D A
[问题已关闭] 标记为“不予修复”,因为内存泄漏在正常使用情况下不会发生。 - D A
你可以尝试使用plt.switch_backend('agg') - undefined

0
我使用plt.close("all"),它按预期工作。

-1
晚回答了,但这对我有用。我有一个生成许多图的长序列代码,它总是在过程结束时耗尽所有RAM。 与其在每个图完成后调用fig.close(),我已经简单地重新定义了plt.figure函数,如下所示,以便自动完成:
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而不是重新定义它。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接