对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基础教程之简单入门说明(变量和控制语言使用方法)
Mar 25 Python
python实现多线程暴力破解登陆路由器功能代码分享
Jan 04 Python
python3批量删除豆瓣分组下的好友的实现代码
Jun 07 Python
Python爬取三国演义的实现方法
Sep 12 Python
一步步教你用Python实现2048小游戏
Jan 19 Python
Anaconda 离线安装 python 包的操作方法
Jun 11 Python
python实现录音小程序
Oct 26 Python
使用python根据端口号关闭进程的方法
Nov 06 Python
python3实现表白神器
Apr 09 Python
在tensorflow以及keras安装目录查询操作(windows下)
Jun 19 Python
Tensorflow全局设置可见GPU编号操作
Jun 30 Python
教你如何用Python实现人脸识别(含源代码)
Jun 23 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
咖啡产品发展的三大浪潮
2021/03/04 咖啡文化
一个PHP日历程序
2006/12/06 PHP
php桌面中心(一) 创建数据库
2007/03/11 PHP
php操作redis缓存方法分享
2015/06/03 PHP
php提交表单时保留多个空格及换行的文本样式的方法
2017/06/20 PHP
jquery制作搜狐快站页面效果示例分享
2014/02/21 Javascript
举例讲解JavaScript中将数组元素转换为字符串的方法
2015/10/25 Javascript
JS实现的3D拖拽翻页效果代码
2015/10/31 Javascript
基于HTML+CSS,jQuery编写的简易计算器后续(添加了键盘监听)
2016/01/05 Javascript
javascript 正则表达式去空行方法
2017/01/24 Javascript
NodeJS仿WebApi路由示例
2017/02/28 NodeJs
微信小程序 页面传值详解
2017/03/10 Javascript
Vue请求JSON Server服务器数据的实现方法
2018/11/02 Javascript
Vue环境搭建+VSCode+Win10的详细教程
2020/08/19 Javascript
vue+element table表格实现动态列筛选的示例代码
2021/01/14 Vue.js
[02:36]DOTA2英雄基础教程 一击致命幻影刺客
2013/12/06 DOTA
删除目录下相同文件的python代码(逐级优化)
2012/05/25 Python
python搭建简易服务器分析与实现
2012/12/15 Python
scrapy spider的几种爬取方式实例代码
2018/01/25 Python
Python中将变量按行写入txt文本中的方法
2018/04/03 Python
Python实现对字典分别按键(key)和值(value)进行排序的方法分析
2018/12/19 Python
Python操作MySQL数据库的两种方式实例分析【pymysql和pandas】
2019/03/18 Python
Python3.5 Pandas模块缺失值处理和层次索引实例详解
2019/04/23 Python
Django组件cookie与session的具体使用
2019/06/05 Python
Python自动抢红包教程详解
2019/06/11 Python
Python图像处理PIL各模块详细介绍(推荐)
2019/07/17 Python
在django中图片上传的格式校验及大小方法
2019/07/28 Python
Python利用多线程同步锁实现多窗口订票系统(推荐)
2019/12/22 Python
Python验证码截取识别代码实例
2020/05/16 Python
Python通过yagmail实现发送邮件代码解析
2020/10/27 Python
Mountain Hardwear官网:攀岩服装和户外装备
2019/09/26 全球购物
存储过程和sql语句的优缺点
2014/07/02 面试题
电子商务助理求职自荐信
2014/04/10 职场文书
快递员岗位职责
2014/09/12 职场文书
入党宣誓大会后的感想
2015/08/10 职场文书
教学工作总结范文5篇
2019/08/19 职场文书