对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 multiprocessing.Manager介绍和实例(进程间共享数据)
Nov 21 Python
在Mac OS上搭建Python的开发环境
Dec 24 Python
python用模块zlib压缩与解压字符串和文件的方法
Dec 16 Python
Python快速从注释生成文档的方法
Dec 26 Python
python pandas实现excel转为html格式的方法
Oct 23 Python
详解Python3注释知识点
Feb 19 Python
python3实现斐波那契数列(4种方法)
Jul 15 Python
python匿名函数的使用方法解析
Oct 10 Python
解决Alexnet训练模型在每个epoch中准确率和loss都会一升一降问题
Jun 17 Python
pycharm中使用request和Pytest进行接口测试的方法
Jul 31 Python
python如何设置静态变量
Sep 07 Python
Python包argparse模块常用方法
Jun 04 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 加密解密内部算法
2010/04/22 PHP
一个典型的PHP分页实例代码分享
2011/07/28 PHP
解析php获取字符串的编码格式的方法(函数)
2013/06/21 PHP
Yii框架的布局文件实例分析
2019/09/04 PHP
Laravel 实现添加多语言提示信息
2019/10/25 PHP
js 关键词高亮(根据ID/tag高亮关键字)案例介绍
2013/01/21 Javascript
基于jquery的has()方法以及与find()方法以及filter()方法的区别详解
2013/04/26 Javascript
jquery sortable的拖动方法示例详解
2014/01/16 Javascript
js实现jquery的offset()方法实例
2015/01/10 Javascript
node.js操作mongodb简单示例分享
2017/05/25 Javascript
JavaScript实现简单图片轮播效果
2017/08/21 Javascript
js中json对象和字符串的理解及相互转化操作实现方法
2017/09/22 Javascript
vuex中使用对象展开运算符的示例
2017/09/25 Javascript
浅谈angular表单提交中ng-submit的默认使用方法
2018/09/30 Javascript
mpvue全局引入sass文件的方法步骤
2019/03/06 Javascript
vue设计一个倒计时秒杀的组件详解
2019/04/06 Javascript
Layui数据表格跳转到指定页的实现方法
2019/09/05 Javascript
原生JavaScript实现换肤
2021/02/19 Javascript
Python模块学习 re 正则表达式
2011/05/19 Python
python读文件逐行处理的示例代码分享
2013/12/27 Python
python进阶教程之函数对象(函数也是对象)
2014/08/30 Python
Python中return语句用法实例分析
2015/08/04 Python
Python中使用asyncio 封装文件读写
2016/09/11 Python
使用Python3 编写简单信用卡管理程序
2016/12/21 Python
python发送告警邮件脚本
2018/09/17 Python
Python获取航线信息并且制作成图的讲解
2019/01/03 Python
Python参数解析模块sys、getopt、argparse使用与对比分析
2019/04/02 Python
linux环境中没有网络怎么下载python
2019/07/07 Python
Pytorch 实现sobel算子的卷积操作详解
2020/01/10 Python
Python 安装 virturalenv 虚拟环境的教程详解
2020/02/21 Python
解决Python中报错TypeError: must be str, not bytes问题
2020/04/07 Python
Java基础知识面试题
2014/03/25 面试题
汽车技术服务与营销专业在籍生自荐信
2013/09/28 职场文书
小学六年级学生评语
2014/04/22 职场文书
负责人任命书范本
2014/06/04 职场文书
详解Mysql 函数调用优化
2021/04/07 MySQL