对python程序内存泄漏调试的记录


Posted in Python onJune 11, 2018

问题描述

调试python程序时,用下面这段代码,可以获得进程占用系统内存值。程序跑一段时间后,就能画出进程对内存的占用情况。

def memory_usage_psutil():
 # return the memory usage in MB
 import psutil,os
 process = psutil.Process(os.getpid())
 mem = process.memory_info()[0] / float(2 ** 20)
 return mem

发现进程的内存占用一直再上涨,而这从逻辑上来说是不正常的,所以想到程序可能发生了Memory Leak。

python程序的Mem Leak

python程序不可能像C/C++一样出现malloc了的内存没有free这样的Memory Leak。但也会遇到“逻辑上没free”的情况,如下代码所示。

def foo(a=[]):
 a.append(time.time())
 return a

参数a这样可迭代的对象,稍不注意,它就能增长的很快。说白了,python的Memory Leak,就是“进程占用的内存莫名其妙一直再升高”。进程占用内存一直升高,与逻辑预期不一致,就可能发生了Memory Leak。

以下面程序为例说明Memory Leak调试的过程:

def memory_usage_psutil():
 # return the memory usage in MB
 import psutil,os
 process = psutil.Process(os.getpid())
 mem = process.memory_info()[0] / float(2 ** 20)
 return mem

def get_current_obj(a=[]):
 a.append([0]*1000)
 return a

def main(): 
 obj = []
 for i in range(10000):
 obj = get_current_obj(obj)
 if(i%100==0):
  print(memory_usage_psutil())

if __name__=='__main__':
 main()

调试过程

用pmap -x [pid]查看进程占用的堆内存大小

首先想到,会不会是上面用的memory_usage_psutil函数统计错误呢。

先运行程序,再用pmap查看,发现进程内存占用确实很高。多次执行该命令,也可以发现内存一直升高。

对python程序内存泄漏调试的记录

强制执行GC(gc.collect())

在需要执行GC的地方加上gc.collect()

def main(): 
 obj = []
 for i in range(10000):
 obj = get_current_obj(obj)
 import gc;gc.collect()
 if(i%100==0):
  print(memory_usage_psutil())

可以看到,强制GC后,程序执行变慢,但内存依然不断升高。

使用memory_profiler查看

安装memory_profiler

pip install -U memory_profiler

用@profile修饰需要查看内存的函数

@profile
def main(): 
 obj = []
 for i in range(10000):
 obj = get_current_obj(obj)
 if(i%100==0):
  print(memory_usage_psutil())

用如下命令运行程序

python -m memory_profiler main.py

可以看到程序执行完成后,输出结果如下

Line # Mem usage Increment Line Contents
================================================
 12 28.570 MiB 0.000 MiB @profile
 13    def main():
 14 28.570 MiB 0.000 MiB obj = []
 15 106.203 MiB 77.633 MiB for i in range(10000):
 16 106.203 MiB 0.000 MiB  obj = get_current_obj(obj)
 17 106.203 MiB 0.000 MiB  if(i%100==0):
 18 105.445 MiB -0.758 MiB  print(memory_usage_psutil())

这样就能看到导致内存上涨最快的那几行代码。

用guppy查看python对象占用的堆内存大小

将main修改如下,即可查看python对堆内存的占用量。

def main(): 
 obj = []
 for i in range(10000):
 obj = get_current_obj(obj)
 if(i%100==0):
  print(memory_usage_psutil())
  from guppy import hpy;hxx = hpy();heap = hxx.heap()
  print(heap)

下面就是输出结果,python程序中各个对象对内存的占用从大到小排列。

Index Count % Size % Cumulative % Kind (class / dict of class)
 0 10124 22 81944416 95 81944416 95 list
 1 16056 34 1325464 2 83269880 96 str
 2 9147 20 745616 1 84015496 97 tuple
 3 102 0 366480 0 84381976 98 dict of module
 4 287 1 313448 0 84695424 98 dict of type
 5 2426 5 310528 0 85005952 98 types.CodeType
 6 2364 5 283680 0 85289632 99 function
 7 287 1 256960 0 85546592 99 type
 8 169 0 192088 0 85738680 99 dict (no owner)
 9 123 0 142728 0 85881408 99 dict of class

可以从结果中看到,95%的进程内存,都被一个list占用。

还可以通过下面这种方式,查看这个占内存最大的list中的数据类型。

from guppy import hpy;hxx = hpy();byrcs = hxx.heap().byrcs; byrcs[0].byid

关于guppy的详细用法,可以看这里(http://smira.ru/wp-content/uploads/2011/08/heapy.html)。

以上这篇对python程序内存泄漏调试的记录就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
总结Python中逻辑运算符的使用
May 13 Python
python实现文件快照加密保护的方法
Jun 30 Python
Python基于select实现的socket服务器
Apr 13 Python
利用aardio给python编写图形界面
Aug 21 Python
Python批量合并有合并单元格的Excel文件详解
Apr 05 Python
python重试装饰器的简单实现方法
Jan 31 Python
Python求一批字符串的最长公共前缀算法示例
Mar 02 Python
python使用MQTT给硬件传输图片的实现方法
May 05 Python
Python3 合并二叉树的实现
Sep 30 Python
完美解决pyinstaller打包报错找不到依赖pypiwin32或pywin32-ctypes的错误
Apr 01 Python
Python实现一个优先级队列的方法
Jul 31 Python
详解python metaclass(元类)
Aug 13 Python
Python3中正则模块re.compile、re.match及re.search函数用法详解
Jun 11 #Python
python检测空间储存剩余大小和指定文件夹内存占用的实例
Jun 11 #Python
Python3多进程 multiprocessing 模块实例详解
Jun 11 #Python
Python3中的列表生成式、生成器与迭代器实例详解
Jun 11 #Python
python xlsxwriter创建excel图表的方法
Jun 11 #Python
python操作excel的包(openpyxl、xlsxwriter)
Jun 11 #Python
django 使用 request 获取浏览器发送的参数示例代码
Jun 11 #Python
You might like
php不用正则验证真假身份证
2013/11/06 PHP
PHP内核探索之变量
2015/12/22 PHP
PHP查询并删除数据库多列重复数据的方法(利用数组函数实现)
2016/02/23 PHP
ThinkPHP3.2.1图片验证码实现方法
2016/08/19 PHP
php微信公众号开发(4)php实现自定义关键字回复
2016/12/15 PHP
PHP连接MySQL数据库操作代码实例解析
2020/07/11 PHP
location.href语句与火狐不兼容的问题
2010/07/04 Javascript
使用jquery为table动态添加行的实现代码
2011/03/30 Javascript
JavaScript设计模式之观察者模式(发布者-订阅者模式)
2014/09/24 Javascript
javascript中sort()的用法实例分析
2015/01/30 Javascript
JavaScript中Number.MIN_VALUE属性的使用示例
2015/06/04 Javascript
JavaScript仿支付宝密码输入框
2015/12/29 Javascript
超赞的jQuery图片滑块动画特效代码汇总
2016/01/25 Javascript
javascript HTML5 Canvas实现圆盘抽奖功能
2016/04/11 Javascript
js多个物体运动功能实例分析
2016/12/20 Javascript
vue组件实例解析
2017/01/10 Javascript
数组Array的排序sort方法
2017/02/17 Javascript
JS实现的点击表头排序功能示例
2017/03/27 Javascript
webpack进阶——缓存与独立打包的用法
2017/08/02 Javascript
详解vue 模拟后台数据(加载本地json文件)调试
2017/08/25 Javascript
原生JS实现烟花效果
2020/03/10 Javascript
vue props 一次传多个值实例
2020/07/22 Javascript
简单理解Python中的装饰器
2015/07/31 Python
Scrapy基于selenium结合爬取淘宝的实例讲解
2018/06/13 Python
python内存管理机制原理详解
2019/08/12 Python
在Anaconda3下使用清华镜像源安装TensorFlow(CPU版)
2020/04/19 Python
Python用K-means聚类算法进行客户分群的实现
2020/08/23 Python
html5 利用canvas实现超级玛丽简单动画
2013/09/06 HTML / CSS
学生实习介绍信
2014/01/15 职场文书
护士自我鉴定总结
2014/03/24 职场文书
舞蹈教育学专业求职信
2014/06/29 职场文书
财务稽核岗位职责
2015/04/13 职场文书
甲午风云观后感
2015/06/02 职场文书
如何写好一份优秀的工作总结?
2019/06/21 职场文书
利用html+css实现菜单栏缓慢下拉效果的示例代码
2021/03/30 HTML / CSS
windows11选中自动复制怎么开启? Win11自动复制所选内容的方法
2022/07/23 数码科技