需要帮助识别涉及matplotlib和烧瓶的内存泄漏

时间:2011-10-12 13:29:11

标签: python sqlite matplotlib mod-wsgi flask

我使用了使用matplotlib进行绘图的烧瓶框架编写了一个小的webapp。问题是,每次创建绘图时,该过程都会消耗更多内存。

我已经使用mod_wsgi部署了一个带有.wsgi文件的应用程序,看起来就像这样:

from yourapplication import app as application

当我访问创建情节的网址时,问题就开始了。该函数创建一个绘图仪对象,当它被启动时,从sqlite3数据库获取相关数据(数据由大约30个整数和相同数量的日期时间对象组成),使用matplotlib创建一个绘图并返回一个StringIO对象,然后在屏幕上显示。

这是功能的结束。可以看到整个班级here

    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 :(得分:2)

每次调用plot_month函数后执行此操作都可以解决泄漏问题。

import gc
gc.collect()

答案 1 :(得分:0)

发布此信息以防将来对某人有帮助。

我遇到了同样的问题,我认为axel22提供的答案并不能为我解决问题。

经过一番修补,我意识到存在两个问题:

  1. 我没有清除Matplotlib图形,将其永久保留在内存中
  2. 我在代码错误的部分调用了垃圾收集器

第一个问题

我正在做这样的事情( INCORRECT ):

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 的范围之外调用它。

此DID不起作用(错误):

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()

答案 2 :(得分:0)

当我的网站需要使用Flask循环生成一系列图形时,我遇到了与您相同的内存泄漏问题。 matplotlib的documentation“如何在Web应用程序服务器中使用Matplotlib”部分下,实际上提到要避免使用matplotlib.pyplot并使用matplotlib.figure.Figure来代替避免内存泄漏。请注意,您需要Matplotlib 3.1或更高版本。

取决于构建图形的方式(CLI与OO接口)。将Pyplot类转换为Figure类非常简单。 发件人:

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

收件人:

from matplotlib.figure import Figure
fig = Figure()

然后将那些无法使用的代码从CLI API替换为面向对象的API。