python 内存监控模块之memory_profiler
0. memory_profiler是干嘛的
This is a python module for monitoring memory consumption of a process as well as line-by-line analysis of memory consumption for python programs. It is a pure python module and has the psutil module as optional (but highly recommended) dependencies.
memory_profiler是监控python进程的神器,它可以分析出每一行代码所增减的内存状况。
1. 入门例子
#del3.py
import time
@profile
def my_func():
a = [1] * (10 ** 6)
b = [2] * (2 * 10 ** 7)
time.sleep(10)
del b
del a
print "+++++++++" if __name__ == '__main__':
my_func()
结果
$python -m memory_profiler del3.py
+++++++++
Filename: del3.py Line # Mem usage Increment Line Contents
================================================
2 10.293 MiB 0.000 MiB @profile
3 def my_func():
4 17.934 MiB 7.641 MiB a = [1] * (10 ** 6)
5 170.523 MiB 152.590 MiB b = [2] * (2 * 10 ** 7)
6 170.527 MiB 0.004 MiB time.sleep(10)
7 17.938 MiB -152.590 MiB del b
8 10.305 MiB -7.633 MiB del a
9 10.309 MiB 0.004 MiB print "+++++++++"
代码执行一遍,然后给出具体代码在某一步占用的内存,通过内存加减可以看出某个对象的大小。
2. 对象不删除,直接赋值内存是否会继续增长
#对比1
@profile
def my_func():
a = 'a' * 1024 * 1024 * 1024;
a = 'a' * 1024 * 1024
a = 'a' * 1024
del a
print "+++++++++" if __name__ == '__main__':
my_func()
结果
Line # Mem usage Increment Line Contents
================================================
1 10.293 MiB 0.000 MiB @profile
2 def my_func():
3 1034.301 MiB 1024.008 MiB a = 'a' * 1024 * 1024 * 1024;
4 11.285 MiB -1023.016 MiB a = 'a' * 1024 * 1024
5 11.285 MiB 0.000 MiB a = 'a' * 1024
6 11.285 MiB 0.000 MiB del a
7 11.289 MiB 0.004 MiB print "+++++++++"
#对比2
@profile
def my_func():
a = 'a' * 1024 * 1024 * 1024;
del a
a = 'a' * 1024 * 1024
del a
a = 'a' * 1024
del a
print "+++++++++" if __name__ == '__main__':
my_func()
结果
Line # Mem usage Increment Line Contents
================================================
1 10.293 MiB 0.000 MiB @profile
2 def my_func():
3 1034.301 MiB 1024.008 MiB a = 'a' * 1024 * 1024 * 1024;
4 10.297 MiB -1024.004 MiB del a
5 11.285 MiB 0.988 MiB a = 'a' * 1024 * 1024
6 11.285 MiB 0.000 MiB del a
7 11.285 MiB 0.000 MiB a = 'a' * 1024
8 11.285 MiB 0.000 MiB del a
9 11.289 MiB 0.004 MiB print "+++++++++"
结论:是否 del对象没有影响,新赋的值会替代旧的值
3. 对象赋值是否会增加同样的内存
#对比1
@profile
def my_func():
a = 'a' * 1024 * 1024 * 1024;
b = a
del a
print "+++++++++" if __name__ == '__main__':
my_func()
结果
Line # Mem usage Increment Line Contents
================================================
1 10.293 MiB 0.000 MiB @profile
2 def my_func():
3 1034.301 MiB 1024.008 MiB a = 'a' * 1024 * 1024 * 1024;
4 1034.301 MiB 0.000 MiB b = a
5 1034.301 MiB 0.000 MiB del a
6 1034.305 MiB 0.004 MiB print "+++++++++"
#对比2
@profile
def my_func():
a = 'a' * 1024 * 1024 * 1024;
b = a
del a
del b
print "+++++++++" if __name__ == '__main__':
my_func()
结果
Line # Mem usage Increment Line Contents
================================================
1 10.297 MiB 0.000 MiB @profile
2 def my_func():
3 1034.305 MiB 1024.008 MiB a = 'a' * 1024 * 1024 * 1024;
4 1034.305 MiB 0.000 MiB b = a
5 1034.305 MiB 0.000 MiB del a
6 10.301 MiB -1024.004 MiB del b
7 10.305 MiB 0.004 MiB print "+++++++++"
结论,把a赋值给b,内存没有增加。但是只删除其中一个对象的时候,内存不会减。
4. 另一种等价的启动方式
from memory_profiler import profile
@profile(precision=4)
def my_func():
a = 'a' * 1024 * 1024 * 1024;
del a
a = 'a' * 1024 * 1024
del a
a = 'a' * 1024
del a
print "+++++++++" if __name__ == '__main__':
my_func()
结果
$python -m memory_profiler del3.py
+++++++++
Filename: del3.py Line # Mem usage Increment Line Contents
================================================
2 10.3867 MiB 0.0000 MiB @profile(precision=4)
3 def my_func():
4 1034.3945 MiB 1024.0078 MiB a = 'a' * 1024 * 1024 * 1024;
5 10.3906 MiB -1024.0039 MiB del a
6 11.3789 MiB 0.9883 MiB a = 'a' * 1024 * 1024
7 11.3789 MiB 0.0000 MiB del a
8 11.3789 MiB 0.0000 MiB a = 'a' * 1024
9 11.3789 MiB 0.0000 MiB del a
10 11.3828 MiB 0.0039 MiB print "+++++++++"
5. 非python内置对象例子
from memory_profiler import profile
import networkx as nx @profile(precision=4)
def my_func():
a = 'a' * 1024 * 1024 * 1024;
del a
G = nx.Graph()
G.add_node(1)
G.add_nodes_from([i for i in range(10000)])
G.add_nodes_from([i for i in range(10000, 20000)])
G.add_edges_from([(1,2), (1,4), (2, 9), (4, 1), (3, 8)])
del G
print "++++++" if __name__ == '__main__':
my_func()
结果
$python del3.py
++++++
Filename: del3.py Line # Mem usage Increment Line Contents
================================================
4 23.4844 MiB 0.0000 MiB @profile(precision=4)
5 def my_func():
6 1047.4922 MiB 1024.0078 MiB a = 'a' * 1024 * 1024 * 1024;
7 23.4883 MiB -1024.0039 MiB del a
8 23.4883 MiB 0.0000 MiB G = nx.Graph()
9 23.4883 MiB 0.0000 MiB G.add_node(1)
10 31.3359 MiB 7.8477 MiB G.add_nodes_from([i for i in range(10000)])
11 36.9219 MiB 5.5859 MiB G.add_nodes_from([i for i in range(10000, 20000)])
12 36.9219 MiB 0.0000 MiB G.add_edges_from([(1,2), (1,4), (2, 9), (4, 1), (3, 8)])
13 25.9219 MiB -11.0000 MiB del G
14 25.9258 MiB 0.0039 MiB print "++++++"
6. 类怎么使用呢
#del4.py
from memory_profiler import profile class people:
name = ''
age = 0
__weight = 0 def __init__(self,n,a,w):
self.name = n
self.age = a
self.__weight = w @profile(precision=4)
def speak(self):
a = 'a' * 1024
b = 'b' * 1024 * 1024
print("%s is speaking: I am %d years old" % (self.name,self.age)) if __name__ == '__main__':
p = people('tom', 10, 30)
p.speak()
结果
$python del4.py
tom is speaking: I am 10 years old
Filename: del4.py Line # Mem usage Increment Line Contents
================================================
13 9.4219 MiB 0.0000 MiB @profile(precision=4)
14 def speak(self):
15 9.4258 MiB 0.0039 MiB a = 'a' * 1024
16 10.4297 MiB 1.0039 MiB b = 'b' * 1024 * 1024
17 10.4336 MiB 0.0039 MiB print("%s is speaking: I am %d years old" % (self.name,self.age))
7. 随时间内存统计
#test.py
import time @profile
def test1():
n = 10000
a = [1] * n
time.sleep(1)
return a @profile
def test2():
n = 100000
b = [1] * n
time.sleep(1)
return b if __name__ == "__main__":
test1()
test2()
test.py 里有两个两个待分析的函数(@profile标识),为了形象地看出内存随时间的变化,每个函数内sleep 1s,执行
mprof run test.py
如果执行成功,结果这样
$ mprof run test.py
mprof: Sampling memory every 0.1s
running as a Python program...
结果会生成一个.dat文件,如"mprofile_20160716170529.dat",里面记录了内存随时间的变化,可用下面的命令以图片的形式展示出来:
mprof plot

8. API
memory_profiler提供很多包给第三方代码,如
>>> from memory_profiler import memory_usage
>>> mem_usage = memory_usage(-1, interval=.2, timeout=1)
>>> print(mem_usage)
[7.296875, 7.296875, 7.296875, 7.296875, 7.296875]
memory_usage(proc=-1, interval=.2, timeout=None)返回一段时间的内存值,其中proc=-1表示此进程,这里可以指定特定的进程号;interval=.2表示监控的时间间隔是0.2秒;timeout=1表示总共的时间段为1秒。那结果就返回5个值。
如果要返回一个函数的内存消耗,示例
def f(a, n=100):
import time
time.sleep(2)
b = [a] * n
time.sleep(1)
return b from memory_profiler import memory_usage
print memory_usage((f, (2,), {'n' : int(1e6)}))
这里执行了 f(1, n=int(1e6)) ,并返回在执行此函数时的内存消耗。
9. 优化实例
对比str & int
from datetime import datetime
@profile
def my_func():
beg = datetime.now()
a = {}
for i in range():
a[i] = i
#a[str(i)] = i
print "+++++++++"
del a
print "+++++++++"
end = datetime.now()
print "time:", end - beg if __name__ == '__main__':
my_func()
用a[i] = i,结果
+++++++++
+++++++++
time: 0:06:14.790899
Filename: int.py Line # Mem usage Increment Line Contents
================================================
2 14.727 MiB 0.000 MiB @profile
3 def my_func():
4 14.734 MiB 0.008 MiB beg = datetime.now()
5 14.734 MiB 0.000 MiB a = {}
6 94.031 MiB 79.297 MiB for i in range(1000000):
7 94.031 MiB 0.000 MiB a[i] = i
8 #a[str(i)] = i
9 86.402 MiB -7.629 MiB print "+++++++++"
10 38.398 MiB -48.004 MiB del a
11 38.398 MiB 0.000 MiB print "+++++++++"
12 38.398 MiB 0.000 MiB end = datetime.now()
13 38.406 MiB 0.008 MiB print "time:", end - beg
用a[str(i)] = i,结果
+++++++++
+++++++++
time: 0:06:00.288052
Filename: int.py Line # Mem usage Increment Line Contents
================================================
2 14.723 MiB 0.000 MiB @profile
3 def my_func():
4 14.730 MiB 0.008 MiB beg = datetime.now()
5 14.730 MiB 0.000 MiB a = {}
6 140.500 MiB 125.770 MiB for i in range(1000000):
7 #a[i] = i
8 140.500 MiB 0.000 MiB a[str(i)] = i
9 132.871 MiB -7.629 MiB print "+++++++++"
10 38.539 MiB -94.332 MiB del a
11 38.539 MiB 0.000 MiB print "+++++++++"
12 38.539 MiB 0.000 MiB end = datetime.now()
13 38.547 MiB 0.008 MiB print "time:", end - beg
python 内存监控模块之memory_profiler的更多相关文章
- python内存管理机制
主要分为三部分: (1)内存池机制(2)引用计数(3)垃圾回收 (1)内存池机制对于python来说,对象的类型和内存都是在运行时确定的,所以python对象都是动态类型简单来说,python内存分为 ...
- 解读Python内存管理机制
转自:http://developer.51cto.com/art/201007/213585.htm 内存管理,对于Python这样的动态语言,是至关重要的一部分,它在很大程度上甚至决定了Pytho ...
- 转发:[Python]内存管理
本文为转发,原地址为:http://chenrudan.github.io/blog/2016/04/23/pythonmemorycontrol.html 本文主要为了解释清楚python的内存管理 ...
- python 内存泄露的诊断 - 独立思考 - ITeye技术网站
python 内存泄露的诊断 - 独立思考 - ITeye技术网站 python 内存泄露的诊断 博客分类: 编程语言: Python Python多线程Blog.net 对于一个用 python ...
- Python内存优化
实际项目中,pythoner更加关注的是Python的性能问题,之前也写过一篇文章<Python性能优化>介绍Python性能优化的一些方法.而本文,关注的是Python的内存优化,一般说 ...
- 使用gc、objgraph干掉python内存泄露与循环引用!
Python使用引用计数和垃圾回收来做内存管理,前面也写过一遍文章<Python内存优化>,介绍了在python中,如何profile内存使用情况,并做出相应的优化.本文介绍两个更致命的问 ...
- python 内存NoSQL数据库
python 内存NoSQL数据库 来自于网络,经过修改,秉承Open Source精神,回馈网络! #!/usr/bin/python #-*- coding: UTF-8 -*- # # memd ...
- [转] 使用gc && objgraph 优化python内存
转自https://www.cnblogs.com/xybaby/p/7491656.html 使用gc.objgraph干掉python内存泄露与循环引用! 目录 一分钟版本 python内存管 ...
- Python内存优化:Profile,slots,compact dict
实际项目中,pythoner更加关注的是Python的性能问题,之前也写过一篇文章<Python性能优化>介绍Python性能优化的一些方法.而本文,关注的是Python的内存优化,一般说 ...
随机推荐
- Scrum会议9(Beta版本)
组名:天天向上 组长:王森 组员:张政.张金生.林莉.胡丽娜 代码地址:HTTPS:https://git.coding.net/jx8zjs/llk.git SSH:git@git.coding.n ...
- CSS架构
CSS架构 有趣的是,我们通常不这样评判其他语言.一个Rails开发者不会因为他写的代码规范就认为他是一个好的开发者.因为这是最基本的.当然它必须是满 足规范,除此以外还要考虑其他方面:代码是否有可读 ...
- C3P0连接池问题,APPARENT DEADLOCK!!! Creating emergency..... [问题点数:20分,结帖人lovekong]
采用c3p0连接池,每次调试程序,第一次访问时(Tomcat服务器重启后再访问)都会出现以下错误,然后连接库需要很长时间,最终是可以连上的,之后再访问就没问题了,请高手们会诊一下,希望能帮小弟解决此问 ...
- Apache Spark源码走读之11 -- sql的解析与执行
欢迎转载,转载请注明出处,徽沪一郎. 概要 在即将发布的spark 1.0中有一个新增的功能,即对sql的支持,也就是说可以用sql来对数据进行查询,这对于DBA来说无疑是一大福音,因为以前的知识继续 ...
- ThinkPHP 模板截取字符串 【转载】
对于英文字符可使用如下形式(模板中): {$vo.title|substr=,} 如果是中文字符thinkphp提供了msubstr,用法如下: function msubstr($str, $sta ...
- 20145235 《Java程序设计》第9周学习总结
第十六章 整合数据库 JDBC Java语言访问数据库的一种规范,是一套API. JDBC (Java Database Connectivity) API,即Java数据库编程接口,是一组标准的Ja ...
- phpCAS::handleLogoutRequests()关于java端项目登出而php端项目检测不到的测试
首先,假如你有做过cas,再假如你的cas里面有php项目,这个时候要让php项目拥有cas的sso功能,你需要改造你的项目,由于各人的项目不同,但是原理差不多,都是通过从cas服务器获取sessio ...
- Qt调用dll中的功能函数
声明: 事先我已经自己动手写了一个简单的dll文件(myDLL.dll),C版接口的.并且用我前两篇有关DLL文章里面的方法,从dll中导出了导入库(.lib)文件,dll中有两个函数,原型如下: ...
- Compiling Inkscape on Windows
http://wiki.inkscape.org/wiki/index.php/Compiling_Inkscape_on_Windows http://www.oschina.net/news/80 ...
- QList内存释放(看它内部存储的是否是Object,另外还有qDeleteAll)
QList<T> 的释放分两种情况: 1.T的类型为非指针,这时候直接调用clear()方法就可以释放了,看如下测试代码 #include <QtCore/QCoreApplicat ...