对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实现根据指定端口探测服务器/模块部署的方法
Aug 25 Python
搞笑的程序猿:看看你是哪种Python程序员
Jun 12 Python
Python实现比较两个文件夹中代码变化的方法
Jul 10 Python
举例讲解Python中的死锁、可重入锁和互斥锁
Nov 05 Python
Python基于回溯法子集树模板解决0-1背包问题实例
Sep 02 Python
python 平衡二叉树实现代码示例
Jul 07 Python
Laravel+Dingo/Api 自定义响应的实现
Feb 17 Python
在Python中实现函数重载的示例代码
Dec 12 Python
Python线程协作threading.Condition实现过程解析
Mar 12 Python
tensorflow安装成功import tensorflow 出现问题
Apr 16 Python
Pytorch通过保存为ONNX模型转TensorRT5的实现
May 25 Python
20行代码教你用python给证件照换底色的方法示例
Feb 05 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
一个改进的UBB类
2006/10/09 PHP
PHP+JS实现的实时搜索提示功能
2018/03/13 PHP
PHP函数积累总结
2019/03/19 PHP
jquery ajax 同步异步的执行示例代码
2010/06/23 Javascript
javascript 判断中文字符长度的函数代码
2012/08/27 Javascript
dotopAlert 提示用户需安装播放器的代码
2012/09/17 Javascript
JavaScript操作select元素和option的实例代码
2016/01/29 Javascript
js流动式效果显示当前系统时间
2016/05/16 Javascript
JS实现关闭当前页而不弹出提示框的方法
2016/06/22 Javascript
jQuery实现table中的tr上下移动并保持序号不变的实例代码
2016/07/11 Javascript
JS实现焦点图轮播效果的方法详解
2016/12/19 Javascript
javascript监听页面刷新和页面关闭事件方法详解
2017/01/09 Javascript
微信小程序movable view移动图片和双指缩放实例代码
2017/08/08 Javascript
label+input实现按钮开关切换效果的实例
2017/08/16 Javascript
vue2.0设置proxyTable使用axios进行跨域请求的方法
2017/10/19 Javascript
初探js和简单隐藏效果的实例
2017/11/23 Javascript
OkHttp踩坑随笔为何 response.body().string() 只能调用一次
2018/01/08 Javascript
node.js实现微信开发之获取用户授权
2019/03/18 Javascript
如何解决js函数防抖、节流出现的问题
2019/06/17 Javascript
JS实现关闭小广告特效
2021/01/29 Javascript
python计算圆周率pi的方法
2015/07/11 Python
Python向MySQL批量插数据的实例讲解
2018/03/31 Python
Python 忽略warning的输出方法
2018/10/18 Python
Jupyter notebook在mac:linux上的配置和远程访问的方法
2019/01/14 Python
python同时替换多个字符串方法示例
2019/09/17 Python
pygame实现俄罗斯方块游戏(对战篇1)
2019/10/29 Python
Python包,__init__.py功能与用法分析
2020/01/07 Python
Pycharm自带Git实现版本管理的方法步骤
2020/09/18 Python
python读取图片颜色值并生成excel像素画的方法实例
2021/02/19 Python
分厂厂长岗位职责
2013/12/29 职场文书
医学生临床实习自我评价
2014/03/07 职场文书
入股协议书范本
2014/04/14 职场文书
试用期旷工辞退通知书
2015/04/17 职场文书
寻衅滋事罪辩护词
2015/05/21 职场文书
阿里云国际版 使用Nginx作为HTTPS转发代理服务器
2022/05/11 Servers
Win11使用CAD卡顿或者致命错误怎么办?Win11无法正常使用CAD的解决方法
2022/07/23 数码科技