对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爬虫之爬虫框架Scrapy安装配置
Nov 06 Python
python 文件转成16进制数组的实例
Jul 09 Python
python调用虹软2.0第三版的具体使用
Feb 22 Python
python使用BeautifulSoup与正则表达式爬取时光网不同地区top100电影并对比
Apr 15 Python
详解pytorch 0.4.0迁移指南
Jun 16 Python
pytest中文文档之编写断言
Sep 12 Python
Pytorch之contiguous的用法
Dec 31 Python
Pytorch根据layers的name冻结训练方式
Jan 06 Python
python3将变量写入SQL语句的实现方式
Mar 02 Python
django处理select下拉表单实例(从model到前端到post到form)
Mar 13 Python
python中openpyxl和xlsxwriter对Excel的操作方法
Mar 01 Python
Python提取PDF指定内容并生成新文件
Jun 09 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实现的mongodb操作类
2015/05/28 PHP
关于js日期转化为毫秒数“节省20%的效率和和节省9个字符“问题
2012/03/01 Javascript
JS链式调用的实现方法
2013/03/07 Javascript
js弹出模式对话框,并接收回传值的方法
2013/03/12 Javascript
jquery的相对父元素和相对文档定位示例代码
2013/08/02 Javascript
Node.js安装教程和NPM包管理器使用详解
2014/08/16 Javascript
JQuery工具函数汇总
2015/06/15 Javascript
总结十个Angular.js由浅入深的面试问题
2016/08/26 Javascript
jquery ajaxfileupload异步上传插件使用详解
2017/02/08 Javascript
bootstrap折叠调用collapse()后data-parent不生效的快速解决办法
2017/02/23 Javascript
AngularJS全局警告框实现方法示例
2017/05/18 Javascript
JS严格模式知识点总结
2018/02/27 Javascript
JavaScript实现的反序列化json字符串操作示例
2018/07/18 Javascript
vue2.0父子组件间传递数据的方法
2018/08/16 Javascript
Vue 实现列表动态添加和删除的两种方法小结
2018/09/07 Javascript
深入理解JavaScript 中的执行上下文和执行栈
2018/10/23 Javascript
微信小程序云开发之新手环境配置
2019/05/16 Javascript
微信小程序利用Canvas绘制图片和竖排文字详解
2019/06/25 Javascript
Nuxt的动态路由和参数校验操作
2020/11/09 Javascript
[05:10]2014DOTA2国际邀请赛 通往胜利之匙赛场探秘之旅
2014/07/18 DOTA
Python编码时应该注意的几个情况
2013/03/04 Python
python如何以表格形式打印输出的方法示例
2019/06/21 Python
python3多线程知识点总结
2019/09/26 Python
python爬虫爬取监控教务系统的思路详解
2020/01/08 Python
怎么快速自学python
2020/06/22 Python
美国知名运动产品零售商:Foot Locker
2016/07/23 全球购物
英国花园、DIY、电器和家居用品商店:Robert Dyas
2019/03/18 全球购物
药学专业个人自我评价
2013/11/11 职场文书
师范学院美术系毕业生自我鉴定
2014/01/29 职场文书
服装发布会策划方案
2014/05/22 职场文书
竞选班干部演讲稿500字
2014/08/20 职场文书
三严三实对照检查材料思想汇报
2014/09/28 职场文书
喝酒驾驶检讨书
2014/10/01 职场文书
2015年乡镇组织委员工作总结
2015/10/23 职场文书
妇联2016年六一国际儿童节活动总结
2016/04/06 职场文书
求职自我评价参考范文
2019/05/16 职场文书