对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实现bitmap数据结构详解
Feb 17 Python
python 获取当天每个准点时间戳的实例
May 22 Python
Python读取mat文件,并转为csv文件的实例
Jul 04 Python
django框架之cookie/session的使用示例(小结)
Oct 15 Python
python-opencv 将连续图片写成视频格式的方法
Jan 08 Python
bluepy 一款python封装的BLE利器简单介绍
Jun 25 Python
windows中安装Python3.8.0的实现方法
Nov 19 Python
pandas抽取行列数据的几种方法
Dec 13 Python
Python中使用Selenium环境安装的方法步骤
Feb 22 Python
MATLAB 全景图切割及盒图显示的实现步骤
May 14 Python
pandas中DataFrame数据合并连接(merge、join、concat)
May 30 Python
Pyhton爬虫知识之正则表达式详解
Apr 01 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
Apache下禁止php文件被直接访问的解决方案
2013/04/25 PHP
解析PHP中intval()等int转换时的意外异常情况
2013/06/21 PHP
美图秀秀web开放平台--PHP流式上传和表单上传示例分享
2014/06/22 PHP
php调用mysql存储过程实例分析
2014/12/29 PHP
PHP基于单例模式实现的数据库操作基类
2016/01/15 PHP
浅谈PHP无限极分类原理
2019/03/14 PHP
JavaScript中“+=”的应用
2007/02/02 Javascript
jquery数组之存放checkbox全选值示例代码
2013/12/20 Javascript
利用jquery写的左右轮播图特效
2014/02/12 Javascript
javascript如何使用bind指定接收者
2014/05/04 Javascript
JavaScript数值数组排序示例分享
2014/05/27 Javascript
jQuery中removeAttr()方法用法实例
2015/01/05 Javascript
页面内容排序插件jSort使用方法
2015/10/10 Javascript
Node.js项目中调用JavaScript的EJS模板库的方法
2016/03/11 Javascript
微信公众号-获取用户信息(网页授权获取)实现步骤
2016/10/21 Javascript
D3.js中强制异步文件读取同步的几种方法
2017/02/06 Javascript
bootstrap实现动态进度条效果
2017/03/08 Javascript
JS实现百度搜索接口及链接功能实例代码
2018/02/02 Javascript
Vue中的methods、watch、computed的区别
2018/11/26 Javascript
jQuery each和js forEach用法比较
2019/02/27 jQuery
详解Vue 匿名、具名和作用域插槽的使用方法
2019/04/22 Javascript
PYTHON正则表达式 re模块使用说明
2011/05/19 Python
Python中获取对象信息的方法
2015/04/27 Python
Python selenium实现微博自动登录的示例代码
2018/05/16 Python
python环形单链表的约瑟夫问题详解
2018/09/27 Python
python 字典 setdefault()和get()方法比较详解
2019/08/07 Python
PyCharm GUI界面开发和exe文件生成的实现
2020/03/04 Python
英国最大的美妆产品在线零售商之一:Beauty Bay
2017/09/29 全球购物
销售人员职业生涯规划范文
2014/03/01 职场文书
连带责任保证书
2014/04/29 职场文书
学校重阳节活动总结
2015/03/24 职场文书
2015医德医风个人工作总结
2015/04/02 职场文书
企业法律事务工作总结
2015/08/11 职场文书
2016年党员公开承诺书范文
2016/03/24 职场文书
react合成事件与原生事件的相关理解
2021/05/13 Javascript
Vue+Element UI实现概要小弹窗的全过程
2021/05/30 Vue.js