对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类参数self使用示例
Feb 17 Python
python 根据pid杀死相应进程的方法
Jan 16 Python
PyQt5每天必学之带有标签的复选框
Apr 19 Python
使用Python 统计高频字数的方法
Jan 31 Python
pandas.DataFrame的pivot()和unstack()实现行转列
Jul 06 Python
Python3简单爬虫抓取网页图片代码实例
Aug 26 Python
python不同系统中打开方法
Jun 23 Python
Python3爬虫中Ajax的用法
Jul 10 Python
python 根据列表批量下载网易云音乐的免费音乐
Dec 03 Python
python中pow函数用法及功能说明
Dec 04 Python
Python 解决空列表.append() 输出为None的问题
May 23 Python
python通过函数名调用函数的几种方法总结
Jun 07 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程序防止ddos,dns,集群服务器攻击的解决办法
2013/06/18 PHP
PHP多态代码实例
2015/06/26 PHP
php简单处理XML数据的方法示例
2017/05/19 PHP
jQuery jqgrid 对含特殊字符json 数据的 Java 处理方法
2011/01/01 Javascript
jQuery.event兼容各浏览器的event详细解析
2013/12/18 Javascript
javascript图片相似度算法实现 js实现直方图和向量算法
2014/01/14 Javascript
jquery easyui 结合jsp简单展现table数据示例
2014/04/18 Javascript
jQuery中:not选择器用法实例
2014/12/30 Javascript
javascript中的Function.prototye.bind
2015/06/25 Javascript
JavaScript截断字符串的方法
2015/07/15 Javascript
JS简单实现城市二级联动选择插件的方法
2015/08/19 Javascript
jQuery手动点击实现图片轮播特效
2020/04/20 Javascript
jquery层级选择器的实现(匹配后代元素div)
2016/09/05 Javascript
js在ie下打开对话窗口的方法小结
2016/10/24 Javascript
使用BootStrap实现表格隔行变色及hover变色并在需要时出现滚动条
2017/01/04 Javascript
慕课网题目之js实现抽奖系统功能
2017/09/19 Javascript
mpvue构建小程序的方法(步骤+地址)
2018/05/22 Javascript
Vue Promise的axios请求封装详解
2018/08/13 Javascript
详解webpack2异步加载套路
2018/09/14 Javascript
JavaScript实现抖音罗盘时钟
2019/10/11 Javascript
js实现双色球效果
2020/08/02 Javascript
vue路由分文件拆分管理详解
2020/08/13 Javascript
新手该如何学python怎么学好python?
2008/10/07 Python
Python入门学习之字符串与比较运算符
2015/10/12 Python
Python爬虫常用小技巧之设置代理IP
2018/09/13 Python
Python pandas实现excel工作表合并功能详解
2019/08/29 Python
Python嵌入C/C++进行开发详解
2020/06/09 Python
CSS3 box-sizing属性详解
2016/11/15 HTML / CSS
新西兰领先的内衣店:Bendon Lingerie新西兰
2018/07/11 全球购物
英国排名第一的停车场运营商:NCP
2019/08/26 全球购物
美国工业用品采购网站:Zoro.com
2020/10/27 全球购物
高校学生干部的自我评价分享
2013/11/04 职场文书
离婚纠纷代理词
2015/05/23 职场文书
PHP判断是否是json字符串
2021/04/01 PHP
Go 语言中 20 个占位符的整理
2021/10/16 Golang
基于Python编写一个监控CPU的应用系统
2022/06/25 Python