Python 内存优化之 memory-profiler

概述

简单用法

在函数上加装饰器 profile,正常启动
profile 的其他参数都是选填的

1
2
3
4
5
6
7
8
from memory_profiler import profile

@profile(precision=4,stream=open('memory_profiler.log','w+'))
def my_func():
a = [1] * (10 ** 6)
b = [2] * (2 * 10 ** 7)
del b
return a

##

参考文档

该库地址
https://pypi.org/project/memory-profiler/

中文用法简单说明:
https://www.cnblogs.com/rgcLOVEyaya/p/RGC_LOVE_YAYA_603days_1.html
中文详细说明:
https://www.cnblogs.com/kaituorensheng/p/5669861.html

分析方法

逐行打印内存增长

在可疑函数上套上 @profile 装饰器,运行服务进行压测,观察内存占用即可。
如果没有明显的可疑函数,可以从请求/任务的主入口开始进行分析,结合代码逐步定位问题。

1
2
3
4
5
6
7
8
Line #    Mem usage  Increment   Line Contents
==============================================
3 @profile
4 5.97 MB 0.00 MB def my_func():
5 13.61 MB 7.64 MB a = [1] * (10 ** 6)
6 166.20 MB 152.59 MB b = [2] * (2 * 10 ** 7)
7 13.61 MB -152.59 MB del b
8 13.61 MB 0.00 MB return a

随时间内存占用情况

该图无法直接定位问题,只能用于辅助,直接使用 top 也能达到类似效果
image.png

交互式调试

支持 pdb 调试和 IPython 集成

注意事项

循环下

逐行打印下 Increment 表示循环语句最后一次执行时的内存变化,Mem usage 则是最后一次循环累积占用的内存

GC

删除对象不一定会立即释放内存,不同版本行为不一致,内存分析时可以显式调用 gc.collect() 强制释放内存
相关资料:
https://stackoverflow.com/questions/37075939/python-experiment-with-gc-and-memory-profiler
https://stackoverflow.com/questions/26046924/is-it-more-memory-efficient-to-set-variables-to-none-in-python
思考 premature optimization is the root of all evil

profile 的 stream 参数

示例中@profile 的 stream 为 open(‘memory_profiler.log’,’w+’),但是该写法仅限于脚本调试,在服务调试中不好用。
在服务中建议使用日志模块 LogFile,或者将标准输出导出到文件后进行处理。

坚持原创技术分享,您的支持将鼓励我继续创作!