Python中的配置文件内存分配(支持Numpy数组)

时间:2010-07-30 14:30:33

标签: python numpy memory-management profile

我有一个包含大量对象的程序,其中许多是Numpy数组。我的程序很糟糕地交换,我正在尝试减少内存使用量,因为它实际上无法在我的系统上完成当前的内存需求。

我正在寻找一个好的分析器,它可以让我检查各种对象消耗的内存量(我正在设想与cProfile相对应的内存),以便我知道在哪里进行优化。

我听说过关于Heapy的不错的东西,但遗憾的是Heapy不支持Numpy数组,而且我的大多数程序都涉及Numpy数组。

5 个答案:

答案 0 :(得分:12)

如果要调用许多不同的函数并且不确定交换来自何处,那么解决问题的一种方法是使用memory_profiler中的新绘图功能。首先,您必须使用@profile装饰您正在使用的不同功能。为简单起见,我将使用memory_profiler附带的示例examples/numpy_example.py,其中包含两个函数:create_data()process_data()

要运行脚本,而不是使用Python解释器运行它,请使用mprof可执行文件,即

$ mprof run examples/numpy_example.py

这将创建一个名为mprofile_??????????.dat的文件,其中?将保存代表当前日期的数字。要绘制结果,只需键入mprof plot,它就会生成一个与此类似的图(如果你有几个.dat文件,它将始终采用最后一个):

output of memory_profiler's mprof

在这里您可以看到内存消耗,括号表示您何时进入/离开当前功能。这样很容易看出函数process_data()有一个峰值  内存消耗要进一步深入了解您的功能,您可以使用逐行分析器来查看函数中每行的内存消耗。这是用

运行的
python -m memory_profiler examples/nump_example.py

这将为您提供类似于此的输出:

Line #    Mem usage    Increment   Line Contents
================================================
    13                             @profile
    14  223.414 MiB    0.000 MiB   def process_data(data):
    15  414.531 MiB  191.117 MiB       data = np.concatenate(data)
    16  614.621 MiB  200.090 MiB       detrended = scipy.signal.detrend(data, axis=0)
    17  614.621 MiB    0.000 MiB       return detrended

很明显,scipy.signal.detrend正在分配大量内存。

答案 1 :(得分:10)

看看memory profiler。它提供逐行分析和Ipython集成,这使得它非常容易使用:

In [1]: import numpy as np

In [2]: %memit np.zeros(1e7)
maximum of 3: 70.847656 MB per loop

<强>更新

正如@WickedGrey所提到的,在多次调用函数时似乎存在一个错误(see github issue tracker),我可以重现:

In [2]: for i in range(10):
   ...:     %memit np.zeros(1e7)
   ...:     
maximum of 1: 70.894531 MB per loop
maximum of 1: 70.894531 MB per loop
maximum of 1: 70.894531 MB per loop
maximum of 1: 70.894531 MB per loop
maximum of 1: 70.894531 MB per loop
maximum of 1: 70.894531 MB per loop
maximum of 1: 70.902344 MB per loop
maximum of 1: 70.902344 MB per loop
maximum of 1: 70.902344 MB per loop
maximum of 1: 70.902344 MB per loop

但是我不知道结果可能影响到什么范围(在我的例子中似乎没那么多,所以根据你的用例它可能仍然有用)并且当这个问题可能修复时。我在github问了那个问题。

答案 2 :(得分:1)

由于numpy 1.7存在一种半内置的方式来跟踪内存分配:

https://github.com/numpy/numpy/tree/master/tools/allocation_tracking

答案 3 :(得分:0)

在不使用tmp文件时,你能将一些数组保存/腌制到磁盘吗?这就是我过去使用大型阵列时必须做的事情。当然这会减慢程序,但至少它会完成。除非你一次性需要它们吗?

答案 4 :(得分:0)

您是否使用valgrind工具尝试massif

valgrind --tool=massif python yourscript.py

它将创建一个名为massif.out.xxx的文件,您可以通过

进行检查
ms_print massif.out.xxx | less

它有各种有用的信息,但一开始的情节应该是你正在寻找的。另请查看valgrind主页上的massif tutorial

使用valgrind非常先进,可能有更简单的方法来执行您正在寻找的内容。