对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 socket网络编程TCP/IP服务器与客户端通信
Jan 05 Python
VTK与Python实现机械臂三维模型可视化详解
Dec 13 Python
简述Python2与Python3的不同点
Jan 21 Python
使用python将图片按标签分入不同文件夹的方法
Dec 08 Python
利用pyinstaller打包exe文件的基本教程
May 02 Python
对pyqt5中QTabWidget的相关操作详解
Jun 21 Python
pip安装python库的方法总结
Aug 02 Python
python自动生成model文件过程详解
Nov 02 Python
Python Django中间件使用原理及流程分析
Jun 13 Python
Python连接mysql数据库及简单增删改查操作示例代码
Aug 03 Python
python中os.remove()用法及注意事项
Jan 31 Python
如何用 Python 制作 GitHub 消息助手
Feb 20 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的简单采集数据入库程序
2014/07/30 PHP
PHP往XML中添加节点的方法
2015/03/12 PHP
PHP内核学习教程之php opcode内核实现
2016/01/27 PHP
深入了解PHP中的Array数组和foreach
2016/11/06 PHP
php断点续传之文件分割合并详解
2016/12/13 PHP
利用location.hash实现跨域iframe自适应
2010/05/04 Javascript
基于jquery的无限级联下拉框js插件
2011/10/29 Javascript
Javascript拓展String方法小结
2013/07/08 Javascript
JS实现鼠标箭头变成一个燃烧烛光效果的方法
2015/02/28 Javascript
JavaScript实现动态添加,删除行的方法实例详解
2015/07/02 Javascript
详解JavaScript的变量和数据类型
2015/11/27 Javascript
浅谈Cookie的生命周期问题
2016/08/02 Javascript
js 转json格式的字符串为对象或数组(前后台)的方法
2016/11/02 Javascript
js前端实现多图图片上传预览的两个方法(推荐)
2016/11/18 Javascript
使用Vue.js创建一个时间跟踪的单页应用
2016/11/28 Javascript
基于javascript实现按圆形排列DIV元素(二)
2016/12/02 Javascript
使用jQuery操作DOM的方法小结
2017/02/27 Javascript
用nodeJS搭建本地文件服务器的几种方法小结
2017/03/16 NodeJs
jQuery插件FusionWidgets实现的AngularGauge图效果示例【附demo源码】
2017/03/23 jQuery
微信小程序使用websocket通讯的demo,含前后端代码,亲测可用
2019/05/22 Javascript
微信小程序 动态修改页面数据及参数传递过程详解
2019/09/27 Javascript
[02:49]DOTA2完美大师赛首日观众采访
2017/11/23 DOTA
python读取json文件并将数据插入到mongodb的方法
2015/03/23 Python
Python基于pygame模块播放MP3的方法示例
2017/09/30 Python
django框架模型层功能、组成与用法分析
2019/07/30 Python
使用python写的opencv实时监测和解析二维码和条形码
2019/08/14 Python
详解Django将秒转换为xx天xx时xx分
2019/09/27 Python
Django之使用celery和NGINX生成静态页面实现性能优化
2019/10/08 Python
tensorflow 分类损失函数使用小记
2020/02/18 Python
Python tornado上传文件的功能
2020/03/26 Python
广州迈达威.net面试题目
2012/03/10 面试题
竞职演讲稿范文
2014/01/11 职场文书
社区端午节活动方案
2014/01/28 职场文书
“向国旗敬礼”活动策划方案(4篇)
2014/09/27 职场文书
乐山大佛导游词
2015/02/02 职场文书
公司车队管理制度
2015/08/04 职场文书