【问题标题】:python loop increases its memory usage rapidlypython循环迅速增加其内存使用量
【发布时间】:2013-04-18 10:51:45
【问题描述】:

我有一个运行循环的 python 脚本。在这个循环中,函数DoDebugInfo 被调用,每次循环迭代一次。这个函数基本上是使用matplotlib打印一些图片到硬盘,导出一个KML文件并做一些其他的计算,什么都不返回

我遇到的问题是,python 每次运行时,函数 DoDebugInfo 都会消耗越来越多的 RAM。我猜一些变量正在增加每个循环的大小。

我在通话前后添加了以下几行:

print '=== before: ' + str(resource.getrusage(resource.RUSAGE_SELF).ru_maxrss / 1000)
DoDebugInfo(inputs)
print '=== after: ' + str(resource.getrusage(resource.RUSAGE_SELF).ru_maxrss / 1000)

输出是:

=== before: 71598.08
=== after: 170237.952
=== before: 170237.952
=== after: 255696.896
=== before: 255696.896
=== after: 341409.792

如您所见,在调用之前,程序有内存占用,在调用之后它会增加,但在下一次调用之前保持稳定。

这是为什么?既然DoDebugInfo(inputs) 是一个什么都不返回的函数,那么一些变量怎么会留在内存中呢?是否需要在函数结束时清除所有变量?

编辑: DoDebugInfo 导入此函数:

def plot_line(x,y,kind,lab_x,lab_y,filename):
    fig = plt.figure(figsize=(11,6),dpi=300)
    ax = fig.add_subplot(111)
    ax.grid(True,which='both')
    #print 'plotting'
    if type(x[0]) is datetime.datetime:
        #print 'datetime detected'
        ax.plot_date(matplotlib.dates.date2num(x),y,kind)
        ax.fmt_xdata = DateFormatter('%H')
        ax.autoscale_view()
        fig.autofmt_xdate()
    else:   
        #print 'no datetime'
        ax.plot(x,y,kind)
    xlabel = ax.set_xlabel(lab_x)
    ax.set_ylabel(lab_y)
    fig.savefig(filename,bbox_extra_artists=[xlabel], bbox_inches='tight')

def plot_hist(x,Nbins,lab_x,lab_y,filename):
    fig = plt.figure(figsize=(11,6),dpi=300)
    ax = fig.add_subplot(111)
    ax.grid(True,which='both')
    ax.hist(x,Nbins)
    xlabel = ax.set_xlabel(lab_x)
    ax.set_ylabel(lab_y)
    fig.savefig(filename,bbox_extra_artists=[xlabel], bbox_inches='tight')

并使用以下方式将 10 个图形绘制到磁盘上:

plot_line(index,alt,'-','Drive Index','Altitude in m',output_dir + 'name.png')

如果我注释使用plot_line 的行,问题不会发生,因此泄漏应该在这行代码上。

谢谢

【问题讨论】:

  • 向我们展示您的DoDebugInfo 功能。
  • 一个什么都不返回的函数仍然可以改变全局变量,或者使用一个在调用之间没有清理的可变参数。
  • @eumiro 我已经缩小了泄漏的范围,请看看我在DoDebugInfo 中使用的函数。这是某处的泄漏。谢谢
  • @MartijnPieters 该函数不会改变全局变量......我不知道什么是可变参数,但我会检查它。谢谢
  • Martijn 指的是mutable default argument gotcha

标签: python memory-leaks profiler


【解决方案1】:

问题在于创建了如此多且从未关闭的图形。不知何故,蟒蛇让他们都活着。

我加了一行

plt.close()

到我的每个绘图函数plot_lineplot_hist,问题就消失了。

【讨论】:

【解决方案2】:

大小会无限增长吗?即使不再使用,也很少有程序(或库)将堆返回到它们分配的系统,CPython(2.7.3)也不例外。通常的罪魁祸首是malloc,它将按需增加进程内存,将空间返回到free 上的空闲列表,但永远不会取消分配它从系统请求的空间。此示例代码故意占用内存并表明进程使用是有界且有限的:

import resource

def maxrss(start, end, step=1):
    """allocate ever larger strings and show the process rss"""
    for exp in range(start, end, step):
        s = '0' * (2 ** exp)
        print '%5i: %sk' % (exp, 
            resource.getrusage(resource.RUSAGE_SELF).ru_maxrss / 1000)
    # s goes out of scope here and is freed by Python but not returned 
    # to the system

try:
    maxrss(1, 40, 5)
except MemoryError:
    print 'MemoryError'

maxrss(1, 30, 5)

部分输出(在我的机器上)在哪里:

26: 72k
31: 2167k
MemoryError
 1: 2167k
 6: 2167k
 ...
26: 2170k

这表明解释器未能从系统中获取 2**36 字节的堆,但仍有“手头”的内存来填充以后的请求。正如脚本的最后一行演示的那样,内存是供 Python 使用的,即使它当前没有使用它。

【讨论】:

  • 它实际上一直在内存中增长,直到我的 mac 变得难以操作并且 UI 几乎被冻结。我杀死了 python 应用程序,它释放了 4 GB 的 RAM。不知道如果让他再往前走会怎么样……
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-30
相关资源
最近更新 更多