2010-07-30 115 views
26

我有一个包含大量对象的程序,其中很多是Numpy数组。我的程序更换悲惨,我试图减少内存使用,因为它实际上不能满足当前内存要求我的系统。Python中的配置文件内存分配(支持Numpy数组)

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

我听说过关于Heapy的体面的事情,但Heapy不幸地不支持Numpy数组,而我的大部分程序都涉及Numpy数组。

+0

不是你(好)的问题,当然你可以使用大量的D型= np.float32 /的。 astype(np.float32)为32位而不是64位浮点数。 (小心那些默默地做32英寸 - > 64输出的函数) – denis 2010-08-01 10:36:24

回答

0

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

+3

好的,但是分析的要点是我想知道哪些数组我应该写入文件。如果我试图写出所有内容并仅在需要时才将其拉出,那么I/O需求将非常庞大,并且会打败这一点。 – chimeracoder 2010-07-30 18:14:41

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问了这个问题。

+0

https://github.com/fabianp/memory_profiler/issues/9(“调用函数两次时出现错误的结果”)似乎使它成为任何严重应用程序的非启动器。我误解了这个问题吗? – 2013-10-09 02:34:35

+0

@WickedGrey也许你是对的,我从来没有使用过'memory_profiler',只是了解它,但我现在可以重现这个错误。更新了我的答案。 – bmu 2013-10-11 05:37:57

+0

由于memory_profiler查询操作系统是否有足够的内存使用,所以在不同的运行中不太可能会有稍微不同的结果,因为这可能会被诸如IPython历史或Python分配内存的方式所污染(您永远不知道)当该内存被释放时)。因此,结果的差异小于1%对我来说似乎不太可能。 – 2013-10-11 06:47:42

11

如果您正在调用许多不同的功能,并且您不确定从哪里进行交换,则可以使用memory_profiler中的新绘图功能来解决该问题。首先,您必须用@profile修饰您正在使用的不同功能。为简单起见,我将使用一个包含两个功能随memory_profiler的例子examples/numpy_example.pycreate_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分配大量内存。

0

您是否试过valgrindmassif工具?

valgrind --tool=massif python yourscript.py 

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

ms_print massif.out.xxx | less 

它有各种有用的信息进行检查,但情节就在一开始应该是你在找什么。还可以在valgrind主页上查看massif tutorial

使用valgrind是相当先进的,可能有更简单的方法来做你想要的。

1

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

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

+1

神圣的废话,这是超级有用的。谢谢!我有一个功能,其最大内存使用量与其输入数据的大小相乘12倍。但是,现在,感谢那个'track_allocations.py'脚本,我将它降低到了4倍,所以我不会再看到那些烦人的'MemoryError'。唷!可爱的,现在在我的工具箱中。 – 2016-01-11 07:39:19