Python中的内存分配分析(支持Numpy数组)
我有一个程序,里面有很多对象,其中很多是Numpy数组。我的程序运行得很慢,我想减少内存的使用,因为在我现在的系统上,程序根本无法完成。
我在寻找一个好的工具,可以让我查看各种对象消耗的内存量(我想要一个类似于cProfile的内存分析工具),这样我就知道哪里需要优化。
我听说Heapy还不错,但可惜Heapy不支持Numpy数组,而我程序的大部分内容都是Numpy数组。
5 个回答
自从numpy 1.7版本以来,有一种半自带的方式可以用来跟踪内存分配情况:
https://github.com/numpy/numpy/tree/master/tools/allocation_tracking
可以看看 memory profiler。这个工具可以逐行分析代码的内存使用情况,并且和 Ipython
兼容,使用起来非常简单:
In [1]: import numpy as np
In [2]: %memit np.zeros(1e7)
maximum of 3: 70.847656 MB per loop
更新
正如 @WickedGrey 提到的,当一个函数被调用多次时,似乎存在一个bug(查看GitHub问题追踪),我可以复现这个问题:
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 上问过这个问题。
如果你在调用很多不同的函数,但不确定内存交换问题出在哪里,可以试试使用 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 文件,它会总是选择最新的那个):
在这里,你可以看到内存的使用情况,括号表示你进入或离开当前函数的时间。这样就很容易看出 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 正在分配大量的内存。