对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获取当前时间的方法
Jan 14 Python
Python中的深拷贝和浅拷贝详解
Jun 03 Python
python中类和实例如何绑定属性与方法示例详解
Aug 18 Python
python初学者,用python实现基本的学生管理系统(python3)代码实例
Apr 10 Python
Django rstful登陆认证并检查session是否过期代码实例
Aug 13 Python
Python类如何定义私有变量
Feb 03 Python
python使用PIL剪切和拼接图片
Mar 23 Python
python属于解释语言吗
Jun 11 Python
基于Python的图像阈值化分割(迭代法)
Nov 20 Python
教你怎么用python selenium实现自动化测试
May 27 Python
简单介绍Python的第三方库yaml
Jun 18 Python
python迷宫问题深度优先遍历实例
Jun 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
第十节--抽象方法和抽象类
2006/11/16 PHP
PHP将session信息存储到数据库的类实例
2015/03/04 PHP
php防止网站被攻击的应急代码
2015/10/21 PHP
PHP环形链表实现方法示例
2017/09/15 PHP
PHP重置数组为连续数字索引的几种方式总结
2018/03/12 PHP
PHP判断一个变量是否为整数、正整数的方法示例
2019/09/11 PHP
Swoole源码中如何查询Websocket的连接问题详解
2020/08/30 PHP
JS执行删除前的判断代码
2014/02/18 Javascript
一个JavaScript用逗号分割字符串实例
2014/09/22 Javascript
JavaScript中style.left与offsetLeft的使用及区别详解
2016/06/08 Javascript
AngularJS通过$http和服务器通信详解
2016/09/21 Javascript
获取IE浏览器Cookie信息的方法
2017/01/23 Javascript
js输入框使用正则表达式校验输入内容的实例
2017/02/12 Javascript
基于LayUI分页和LayUI laypage分页的使用示例
2017/08/02 Javascript
Angular使用cli生成自定义文件、组件的方法
2018/09/04 Javascript
JS获取月的第几周和年的第几周实例代码
2018/12/05 Javascript
vue实现输入框的模糊查询的示例代码(节流函数的应用场景)
2019/09/01 Javascript
[42:20]2014 DOTA2华西杯精英邀请赛5 24 DK VS NewBee
2014/05/25 DOTA
合并Excel工作薄中成绩表的VBA代码,非常适合教育一线的朋友
2009/04/09 Python
Python中优化NumPy包使用性能的教程
2015/04/23 Python
python类装饰器用法实例
2015/06/04 Python
举例讲解Python编程中对线程锁的使用
2016/07/12 Python
python中的for循环
2018/09/28 Python
python实现批量视频分帧、保存视频帧
2019/05/31 Python
Python实现图片添加文字
2019/11/26 Python
python 消除 futureWarning问题的解决
2019/12/25 Python
Python实现在Windows平台修改文件属性
2020/03/05 Python
微软开源最强Python自动化神器Playwright(不用写一行代码)
2021/01/05 Python
AmazeUI在模态框中嵌入表单形成模态输入框
2020/08/20 HTML / CSS
初级Java程序员面试题
2016/03/03 面试题
面试后感谢信
2014/02/01 职场文书
《三峡》教学反思
2014/03/01 职场文书
反邪教宣传工作方案
2014/05/07 职场文书
群众路线教育实践活动的心得体会
2014/09/03 职场文书
2015年民兵整组工作总结
2015/07/24 职场文书
Win10鼠标轨迹怎么开 Win10显示鼠标轨迹方法
2022/04/06 数码科技