Python内存泄漏和内存溢出的解决方案


Posted in Python onSeptember 26, 2020

一、内存泄漏

像Java程序一样,虽然Python本身也有垃圾回收的功能,但是同样也会产生内存泄漏的问题。
对于一个用 python 实现的,长期运行的后台服务进程来说,如果内存持续增长,那么很可能是有了“内存泄露”。

1、内存泄露的原因

对于 python 这种支持垃圾回收的语言来说,怎么还会有内存泄露? 概括来说,有以下三种原因:

  • 所用到的用 C 语言开发的底层模块中出现了内存泄露。
  • 代码中用到了全局的 list、 dict 或其它容器,不停的往这些容器中插入对象,而忘记了在使用完之后进行删除回收
  • 代码中有“引用循环”,并且被循环引用的对象定义了__del__方法,就会发生内存泄露。

为什么循环引用的对象定义了__del__方法后collect就不起作用了呢?

gc模块最常使用的方法就是gc.collect()方法,使用collect方法对循环引用的对象进行垃圾回收。
如果我们在类中重载了__del__方法。__del__方法定义了在用del语句删除对象时除了释放内存空间以外的操作。
一般而言,在使用了del语句的时候解释器首先会看要删除对象的引用计数,如果为0,那么就释放内存并执行del方法。
在这里,首先del语句出现时本身引用计数就不为0(因为有循环引用的存在),所以解释器不释放内存;
再者,执行collect方法时应该会清除循环引用所产生的无效引用计数从而达到del的目的,对于这两个循环引用对象而言,
python无法判断调用它们的del方法时会不会要用到对方那个对象,比如在进行b.del()时可能会用到b._a也就是a,如果在那之前a已经被释放,那么就彻底GG了。
为了避免这种情况,collect方法默认不对重载了del方法的循环引用对象进行回收,而它们俩的状态也会从unreachable转变为uncollectable。由于是uncollectable的,自然就不会被collect处理,所以就进入了garbage列表。

2、内存泄露的诊断思路

无论是哪种方式的内存泄露,最终表现的形式都是某些 python 对象在不停的增长;因此,首先是要找到这些异常的对象。

3、诊断步骤

用到的工具: gc 模块和 objgraph 模块

gc模块 是Python的垃圾收集器模块,gc使用标记清除算法回收垃圾

objgraph 是一个用于诊断内存问题的工具

  • 1、 在服务程序的循环逻辑中,选择出一个诊断点
  • 2、 在诊断点,插入如下诊断语句  
import gc
import objgraph


### 强制进行垃圾回收 
gc.collect() 

### 打印出对象数目最多的 50 个类型信息 
objgraph.show_most_common_types(limit=50)

4、检查统计信息,找到异常对象

运行加入诊断语句的服务程序,并将打印到屏幕上的统计信息重定向到日志中。运行一段时间后,就可以来分析日志,看看哪些对象在不停的增长。

比如,排查结果可能是:
一个多线程程序,多个线程作为生产者,一个线程作为消费者,通过将一个 tuple 对象送入异步队列进行通信。
由于消费者的处理速度跟不上生产者的速度,又没有进行同步, 导致异步队列中的对象越来越多。

二、内存溢出

1、内存溢出原因

  1. 内存中加载的数据量过于庞大,如一次从数据库取出过多数据
  2. 集合类中有对对象的引用,使用完后未清空,产生了堆积,使得JVM不能回收
  3. 代码中存在死循环或循环产生过多重复的对象实体
  4. 使用的第三方软件中的BUG
  5. 启动参数内存值设定的过小

2、内存溢出的解决方案

第一步,修改JVM启动参数,直接增加内存(-Xms,-Xmx参数一定不要忘记加)

第二步,检查错误日志,查看“OutOfMemory”错误前是否有其 它异常或错误

第三步,对代码进行走查和分析,找出可能发生内存溢出的位置

重点排查以下几点:

  1. 检查对数据库查询中,是否有一次获得全部数据的查询。一般来说,如果一次取十万条记录到内存,就可能引起内存溢出。这个问题比较隐蔽,在上线前,数据库中数据较少,不容易出问题,上线后,数据库中数据多了,一次查询就有可能引起内存溢出。因此对于数据库查询尽量采用分页的方式查询。
  2. 检查代码中是否有死循环或递归调用。
  3. 检查是否有大循环重复产生新对象实体。
  4. 检查List、MAP等集合对象是否有使用完后,未清除的问题。List、MAP等集合对象会始终存有对对象的引用,使得这些对象不能被GC回收。

第四步,使用内存查看工具动态查看内存使用情况

三、内存泄漏和内存溢出的区别

内存溢出是指向JVM申请内存空间时没有足够的可用内存了,就会抛出OOM即内存溢出。

内存泄漏是指,向JVM申请了一块内存空间,使用完后没有释放,由于没有释放,这块内存区域其他类加载的时候无法申请,

同时当前类又没有这块内存空间的内存地址了也无法使用,相当于丢了一块内存,这就是内存泄漏。

值得注意的是内存泄漏最终会导致内存溢出,很好理解,内存丢了很多最后当然内存不够用了。

以上就是Python内存泄漏和内存溢出的解决方案的详细内容,更多关于Python内存泄漏和内存溢出的资料请关注三水点靠木其它相关文章!

Python 相关文章推荐
python实现代理服务功能实例
Nov 15 Python
python完成FizzBuzzWhizz问题(拉勾网面试题)示例
May 05 Python
教你如何将 Sublime 3 打造成 Python/Django IDE开发利器
Jul 04 Python
Python multiprocessing.Manager介绍和实例(进程间共享数据)
Nov 21 Python
python+selenium实现163邮箱自动登陆的方法
Dec 31 Python
python启动应用程序和终止应用程序的方法
Jun 28 Python
Python 生成VOC格式的标签实例
Mar 10 Python
Django调用百度AI接口实现人脸注册登录代码实例
Apr 23 Python
10张动图学会python循环与递归问题
Feb 06 Python
Python通过m3u8文件下载合并ts视频的操作
Apr 16 Python
Python 中 Shutil 模块详情
Nov 11 Python
Python使用plt.boxplot()函数绘制箱图、常用方法以及含义详解
Aug 14 Python
python 两种方法修改文件的创建时间、修改时间、访问时间
Sep 26 #Python
如何使用Python调整图像大小
Sep 26 #Python
小白教你PyCharm从下载到安装再到科学使用PyCharm2020最新激活码
Sep 25 #Python
PyCharm2020最新激活码+激活码补丁(亲测最新版PyCharm2020.2激活成功)
Nov 25 #Python
详解Python中第三方库Faker
Sep 25 #Python
python对批量WAV音频进行等长分割的方法实现
Sep 25 #Python
python连接mysql数据库并读取数据的实现
Sep 25 #Python
You might like
使用XDebug调试及单元测试覆盖率分析
2011/01/27 PHP
ThinkPHP实现递归无级分类――代码少
2015/07/29 PHP
round robin权重轮循算法php实现代码
2016/05/28 PHP
使用tp框架和SQL语句查询数据表中的某字段包含某值
2019/10/18 PHP
页面实时更新时间的JS实例代码
2013/12/18 Javascript
推荐JavaScript实现继承的最佳方式
2014/11/11 Javascript
深入理解JavaScript系列(42):设计模式之原型模式详解
2015/03/04 Javascript
jQuery实现鼠标滑过点击事件音效试听
2015/08/31 Javascript
js console.log打印对像与数组用法详解
2016/01/21 Javascript
详解JavaScript中数组和字符串的lastIndexOf()方法使用
2016/03/13 Javascript
jQuery技巧之让任何组件都支持类似DOM的事件管理
2016/04/05 Javascript
利用原生js和jQuery实现单选框的勾选和取消操作的方法
2016/09/04 Javascript
javascript中活灵活现的Array对象详解
2016/11/30 Javascript
用JavaScript和jQuery实现瀑布流
2017/03/19 Javascript
基于input动态模糊查询的实现方法
2017/12/12 Javascript
javascript、php关键字搜索函数的使用方法
2018/05/29 Javascript
vue.js使用v-if实现显示与隐藏功能示例
2018/07/06 Javascript
微信小程序实现的日期午别医生排班表功能示例
2019/01/09 Javascript
小白教程|一小时上手最流行的前端框架vue(推荐)
2019/04/10 Javascript
详解vue 动态加载并注册组件且通过 render动态创建该组件
2019/05/30 Javascript
Nuxt v-bind绑定img src不显示的解决
2019/12/05 Javascript
原生js实现五子棋游戏
2020/05/28 Javascript
Vue结合路由配置递归实现菜单栏功能
2020/06/16 Javascript
[14:19]2018年度COSER大赛-完美盛典
2018/12/16 DOTA
使用Python的Tornado框架实现一个简单的WebQQ机器人
2015/04/24 Python
python中实现k-means聚类算法详解
2017/11/11 Python
numpy.random.seed()的使用实例解析
2018/02/03 Python
django-crontab实现服务端的定时任务的示例代码
2020/02/17 Python
请用Java实现列出某个目录下的所有文件
2013/09/23 面试题
应届生会计电算化求职信
2013/10/03 职场文书
2014年五一活动策划方案
2014/03/15 职场文书
初中作文评语大全
2014/04/23 职场文书
广播节目策划方案
2014/05/23 职场文书
2014年老干部工作总结
2014/11/21 职场文书
青年文明号创建口号大全
2015/12/25 职场文书
MySQL 原理优化之Group By的优化技巧
2022/08/14 MySQL