对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 过滤字符串的技巧,map与itertools.imap
Sep 06 Python
Python操作Mysql实例代码教程在线版(查询手册)
Feb 18 Python
Python使用random和tertools模块解一些经典概率问题
Jan 28 Python
python使用opencv读取图片的实例
Aug 17 Python
全面分析Python的优点和缺点
Feb 07 Python
Python实现分段线性插值
Dec 17 Python
基于python框架Scrapy爬取自己的博客内容过程详解
Aug 05 Python
python 将视频 通过视频帧转换成时间实例
Apr 23 Python
python实现秒杀商品的微信自动提醒功能(代码详解)
Apr 27 Python
python3中calendar返回某一时间点实例讲解
Nov 18 Python
python spilt()分隔字符串的实现示例
May 21 Python
Pandas自定义选项option设置
Jul 25 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
解析CI即CodeIgniter框架在Nginx下的重写规则
2013/06/03 PHP
PHP mysqli_free_result()与mysqli_fetch_array()函数详解
2016/09/21 PHP
Javascript 修改String 对象 增加去除空格功能(示例代码)
2013/11/30 Javascript
基于jquery实现发送文章到手机的代码
2014/12/26 Javascript
使用jquery 简单实现下拉菜单
2015/01/14 Javascript
jQuery实现的淡入淡出二级菜单效果代码
2015/09/15 Javascript
Javascript中获取浏览器类型和操作系统版本等客户端信息常用代码
2016/06/28 Javascript
bootstrap 下拉多选框进行多选传值问题代码分析
2017/02/14 Javascript
Angular在一个页面中使用两个ng-app的方法(二)
2017/02/20 Javascript
JavaScript事件处理程序详解
2017/09/19 Javascript
vuejs使用$emit和$on进行组件之间的传值的示例
2017/10/04 Javascript
详解node.js 下载图片的 2 种方式
2018/03/02 Javascript
vue项目中jsonp跨域获取qq音乐首页推荐问题
2018/05/30 Javascript
element上传组件循环引用及简单时间倒计时的实现
2018/10/01 Javascript
JS实现随机生成10个手机号的方法示例
2018/12/07 Javascript
JS XMLHttpRequest原理与使用方法深入详解
2020/04/30 Javascript
[00:32]2016完美“圣”典风云人物:Maybe宣传片
2016/12/05 DOTA
Python语言的12个基础知识点小结
2014/07/10 Python
python常见的格式化输出小结
2016/12/15 Python
Python元组拆包和具名元组解析实例详解
2018/03/26 Python
详解Django+uwsgi+Nginx上线最佳实战
2019/03/14 Python
详解python中的生成器、迭代器、闭包、装饰器
2019/08/22 Python
Python如何实现爬取B站视频
2020/05/20 Python
从零开始的TensorFlow+VScode开发环境搭建的步骤(图文)
2020/08/31 Python
Right-on官方网站:日本知名的休闲服装品牌
2019/07/12 全球购物
初中班主任评语大全
2014/04/24 职场文书
读书小明星事迹材料
2014/05/03 职场文书
事业单位考核材料
2014/05/21 职场文书
学习党章的体会
2014/11/07 职场文书
西湖英语导游词
2015/02/06 职场文书
CSS3新特性详解(五):多列columns column-count和flex布局
2021/04/30 HTML / CSS
超详细Python解释器新手安装教程
2021/05/10 Python
matlab xlabel位置的设置方式
2021/05/21 Python
基于Redis的List实现特价商品列表功能
2021/08/30 Redis
详细介绍python操作RabbitMq
2022/04/12 Python
HTML页面点击按钮关闭页面的多种方式
2022/12/24 HTML / CSS