对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中的异常处理简明介绍
Apr 13 Python
Python中的localtime()方法使用详解
May 22 Python
python模块简介之有序字典(OrderedDict)
Dec 01 Python
Python实现将HTML转换成doc格式文件的方法示例
Nov 20 Python
Python实现基于PIL和tesseract的验证码识别功能示例
Jul 11 Python
Python中flatten( )函数及函数用法详解
Nov 02 Python
使用OpenCV获取图像某点的颜色值,并设置某点的颜色
Jun 02 Python
Python如何将模块打包并发布
Aug 30 Python
Python类绑定方法及非绑定方法实例解析
Oct 09 Python
matplotlib交互式数据光标实现(mplcursors)
Jan 13 Python
python 使用openpyxl读取excel数据
Feb 18 Python
matplotlib部件之套索Lasso的使用
Feb 24 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
Linux编译升级php的详细方法
2013/11/04 PHP
CI框架中集成CKEditor编辑器的教程
2014/06/09 PHP
PHP匿名函数和use子句用法实例
2016/03/16 PHP
简单谈谈PHP中的include、include_once、require以及require_once语句
2016/04/23 PHP
限制复选框的最大可选数
2006/07/01 Javascript
基于jQuery的模仿新浪微博时间的组件
2011/10/04 Javascript
Javascript开发之三数组对象实例介绍
2012/11/12 Javascript
javascript中AJAX用法实例分析
2015/01/30 Javascript
微信小程序 Flex布局详解
2016/10/09 Javascript
Vue.js学习示例分享
2017/02/05 Javascript
angular.js 路由及页面传参示例
2017/02/24 Javascript
Vue.js框架路由使用方法实例详解
2017/08/25 Javascript
详解node nvm进行node多版本管理
2017/10/21 Javascript
原生JS实现的双色球功能示例
2018/02/02 Javascript
VUE中v-on:click事件中获取当前dom元素的代码
2018/08/22 Javascript
浅谈angularJS2中的界面跳转方法
2018/08/31 Javascript
微信小程序实现下拉框功能
2019/07/16 Javascript
js 实现 list转换成tree的方法示例(数组到树)
2019/08/18 Javascript
基于element-ui封装表单金额输入框的方法示例
2021/01/06 Javascript
[02:58]魔廷新尊——痛苦女王至宝语音台词节选
2020/06/14 DOTA
python实现从网络下载文件并获得文件大小及类型的方法
2015/04/28 Python
Python实现获取域名所用服务器的真实IP
2015/10/25 Python
基于pycharm导入模块显示不存在的解决方法
2018/10/13 Python
TensorFlow卷积神经网络之使用训练好的模型识别猫狗图片
2019/03/14 Python
使用 Supervisor 监控 Python3 进程方式
2019/12/05 Python
Python使用sys.exc_info()方法获取异常信息
2020/07/23 Python
Python实现简单的猜单词小游戏
2020/10/28 Python
python 中关于pycharm选择运行环境的问题
2020/10/31 Python
一道Delphi面试题
2016/10/28 面试题
企业行政文员岗位职责
2013/12/03 职场文书
医学院校毕业生自荐信范文
2014/01/01 职场文书
新三好学生主要事迹
2014/01/23 职场文书
拾金不昧锦旗标语
2014/06/27 职场文书
雷锋之歌观后感
2015/06/10 职场文书
浅谈哪个Python库才最适合做数据可视化
2021/06/28 Python
总结python多进程multiprocessing的相关知识
2021/06/29 Python