需要帮助识别matplotlib和flask的内存泄漏问题

1 投票
3 回答
4146 浏览
提问于 2025-04-17 04:09

我用flask框架写了一个小的网页应用,这个应用需要用matplotlib来绘图。问题是每次我创建图表时,程序消耗的内存越来越多。

我通过mod_wsgi部署了这个应用,.wsgi文件看起来很简单,如下所示:

from yourapplication import app as application

问题出现在我访问生成图表的那个网址时。这个函数会创建一个绘图对象,当它被初始化时,会从sqlite3数据库中获取相关数据(这些数据大约有30个整数和同样多的日期时间对象),然后用matplotlib生成一个图表,并返回一个StringIO对象,最后在屏幕上显示出来。

这就是这个函数的全部内容。整个类的代码可以在这里查看。

    canvas = FigureCanvas(fig)
    png_output = StringIO.StringIO()
    canvas.print_png(png_output)
    return png_output.getvalue()

当我访问这个网站时,会创建一个大约占用25MB内存的进程。第一次创建图表时,内存使用量增加到30MB,然后每次使用绘图类时大约增加1MB。默认设置是使用5个进程,这样消耗的内存太多了(几分钟内就达到了150MB,而我只能使用80MB)。

我对这些技术(网页框架、apache、数据库)都很陌生,所以我不知道问题可能出在哪里,任何建议都非常感谢!

3 个回答

0

我在用Flask生成一系列图表的时候,也遇到了和你一样的内存泄漏问题。在matplotlib的文档中,有一部分提到在网页应用中使用matplotlib时,建议不要用matplotlib.pyplot,而是用matplotlib.figure.Figure来避免内存泄漏。需要注意的是,你的Matplotlib版本要在3.1或以上。

这取决于你是如何构建图表的(命令行接口还是面向对象接口)。把Pyplot类换成Figure类其实很简单。

import matplotlib.pyplot as plt
fig = plt.figure()

然后只需要把那些在命令行API中不工作的代码替换成面向对象API的代码就可以了。

from matplotlib.figure import Figure
fig = Figure()
1

发这个是希望能帮助到未来的某个人。

我遇到了同样的问题,觉得axel22给出的答案对我没有用。

经过一番折腾,我发现有两个问题:

  1. 我没有清理Matplotlib的图形,导致它一直占用内存
  2. 我在代码的错误位置调用了垃圾回收器

第一个问题

我之前是这样做的(错误):

fig = util.create_figure(....)
output = io.BytesIO()
canvas = FigureCanvas(fig)
canvas.print_png(output)

但我应该这样做(正确):

fig = util.create_figure(....)
output = io.BytesIO()
canvas = FigureCanvas(fig)
canvas.print_png(output)
# Clears the figure from memory
fig.clf()

第二个问题

我在代码的错误位置调用了垃圾回收器。你需要在FigureCanvas调用的范围之外去调用它。

这样做是没有用的(错误):

import gc

def do_something():
    canvas = FigureCanvas(fig)
    png_output = StringIO.StringIO()
    canvas.print_png(png_output)
    gc.collect()
    return png_output.getvalue()

do_something()

但这样做就有效了(正确):

import gc

def do_something():
    canvas = FigureCanvas(fig)
    png_output = StringIO.StringIO()
    canvas.print_png(png_output)
    return png_output.getvalue()

do_something()
gc.collect()
3

在每次调用plot_month函数之后这样做,就解决了内存泄漏的问题。

import gc
gc.collect()

撰写回答