前言

最近用paddlepaddle,发现训练每个epoch时,内存都会增加几百兆,这明显就是出现了内存泄漏。python中内存泄露的原因比C++(一般就是动态内存分配)更加隐蔽,可以借助memory_profiler这个包监控python代码的内存使用。

安装

直接pip安装就完事了

1
pip install memory_profiler

简单使用

只需要在.py文件中导入memory_profiler包中的profiler方法,然后作为某个函数的装饰器,就能够记录该函数内部代码的内存使用情况了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# learn_mprof.py
from memory_profiler import profile
import numpy as np

@profile
def count():
print('+++++++++++')
a = 0;
b = 1;
c = a + b
print('a+b=c')
print('{}+{}={}'.format(a, b, c))
print('+++++++++++')
arr = np.ones([1000, 1000])
print(arr.shape)
print('+++++++++++')

if __name__ == '__main__':
count()

然后运行:

1
python learn_mprof.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
+++++++++++
a+b=c
0+1=1
+++++++++++
(1000, 1000)
+++++++++++
Filename: learn_mprof.py

Line # Mem usage Increment Occurrences Line Contents
=============================================================
4 53.4 MiB 53.4 MiB 1 @profile
5 def count():
6 53.4 MiB 0.0 MiB 1 print('+++++++++++')
7 53.4 MiB 0.0 MiB 1 a = 0;
8 53.4 MiB 0.0 MiB 1 b = 1;
9 53.4 MiB 0.0 MiB 1 c = a + b
10 53.4 MiB 0.0 MiB 1 print('a+b=c')
11 53.4 MiB 0.0 MiB 1 print('{}+{}={}'.format(a, b, c))
12 53.4 MiB 0.0 MiB 1 print('+++++++++++')
13 61.1 MiB 7.7 MiB 1 arr = np.ones([1000, 1000])
14 61.1 MiB 0.0 MiB 1 print(arr.shape)
15 61.1 MiB 0.0 MiB 1 print('+++++++++++')

Mem usage表示当前内存使用,Increment表示该行代码的内存增量,Occurences表示该行代码运行了几次。

如果要找内存泄漏,直接看Increment就OK了;如果想找内存瓶颈,就看Mem usage。

记录时间-内存的使用情况

如果想记录.py文件运行时,内存使用随时间的变化,也很简单,直接运行:

1
mprof run learn_mprof.py

输出结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
mprof: Sampling memory every 0.1s
running new process
running as a Python program...
+++++++++++
a+b=c
0+1=1
+++++++++++
(1000, 1000)
+++++++++++
Filename: learn_mprof.py

Line # Mem usage Increment Occurrences Line Contents
=============================================================
4 53.6 MiB 53.6 MiB 1 @profile
5 def count():
6 53.6 MiB 0.0 MiB 1 print('+++++++++++')
7 53.6 MiB 0.0 MiB 1 a = 0;
8 53.6 MiB 0.0 MiB 1 b = 1;
9 53.6 MiB 0.0 MiB 1 c = a + b
10 53.6 MiB 0.0 MiB 1 print('a+b=c')
11 53.6 MiB 0.0 MiB 1 print('{}+{}={}'.format(a, b, c))
12 53.6 MiB 0.0 MiB 1 print('+++++++++++')
13 61.3 MiB 7.7 MiB 1 arr = np.ones([1000, 1000])
14 61.3 MiB 0.0 MiB 1 print(arr.shape)
15 61.3 MiB 0.0 MiB 1 print('+++++++++++')

此时,在运行目录中会多出一个mprofile_xxxxxxxxxxxx.dat文件,可以通过这个文件画出时间-内存图:

1
mprof plot mprofile_xxxxxxxxxxxxxxxx.dat

效果: