Python内存泄漏和内存溢出的解决方案
作者:posted 发布时间:2022-02-10 11:46:55
一、内存泄漏
像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、内存溢出原因
内存中加载的数据量过于庞大,如一次从数据库取出过多数据
集合类中有对对象的引用,使用完后未清空,产生了堆积,使得JVM不能回收
代码中存在死循环或循环产生过多重复的对象实体
使用的第三方软件中的BUG
启动参数内存值设定的过小
2、内存溢出的解决方案
第一步,修改JVM启动参数,直接增加内存(-Xms,-Xmx参数一定不要忘记加)
第二步,检查错误日志,查看“OutOfMemory”错误前是否有其 它异常或错误
第三步,对代码进行走查和分析,找出可能发生内存溢出的位置
重点排查以下几点:
检查对数据库查询中,是否有一次获得全部数据的查询。一般来说,如果一次取十万条记录到内存,就可能引起内存溢出。这个问题比较隐蔽,在上线前,数据库中数据较少,不容易出问题,上线后,数据库中数据多了,一次查询就有可能引起内存溢出。因此对于数据库查询尽量采用分页的方式查询。
检查代码中是否有死循环或递归调用。
检查是否有大循环重复产生新对象实体。
检查List、MAP等集合对象是否有使用完后,未清除的问题。List、MAP等集合对象会始终存有对对象的引用,使得这些对象不能被GC回收。
第四步,使用内存查看工具动态查看内存使用情况
三、内存泄漏和内存溢出的区别
内存溢出是指向JVM申请内存空间时没有足够的可用内存了,就会抛出OOM即内存溢出。
内存泄漏是指,向JVM申请了一块内存空间,使用完后没有释放,由于没有释放,这块内存区域其他类加载的时候无法申请,
同时当前类又没有这块内存空间的内存地址了也无法使用,相当于丢了一块内存,这就是内存泄漏。
值得注意的是内存泄漏最终会导致内存溢出,很好理解,内存丢了很多最后当然内存不够用了。
来源:https://www.cnblogs.com/Zzbj/p/13532156.html
猜你喜欢
- 在第一部分中,我们主要讲解了一下如何用列表元素来实现柱状图效果。其中需要特别注意的就是相对定位和绝对定位的的使用。在本节中,将来讨论一下使用
- 本文实例为大家分享了python实现通讯录系统的具体代码,供大家参考,具体内容如下一、首先,给大家看一下这个系统的主菜单效果如下:二、步骤分
- InnoDB给MySQL提供了具有提交,回滚和崩溃恢复能力的事务安全(ACID兼容)存储引擎。InnoDB锁定在行级并且也在SELECT语句
- ASCII码转换为int:ord('A') 65int转为ASCII码:chr(65) 'A'题目内容:实现
- 这里的Counter是指collections中的Counter,通过Counter可以实现字典的创建以及字典key出现频次的统计。然而,使
- python中通过虚拟化出来一个空间,与主环境完全隔离,避免项目中对于环境要求,造成的插件版本混乱(python特别吃环境)mac 的配置前
- 示例代码: BulkStockBll bll = new BulkStockBll(); DataSet ds = bll.GetBulkS
- python中数据处理是比较方便的,经常用的就是读写文件,提取数据等,本博客主要介绍其中的一些用法。Pandas是一个强大的分析结构化数据的
- 大概在九九年做游戏网站的时候,就对文章的发布感到麻烦,不过那会儿玩ASP不精。只是将就用着。在遇到长文件 10000 字时网页就是一大片长了
- 很多时候,我们都在说设计需要引导用户,尤其是在对初级用户的引导上,很大程度决定着产品能否快速聚拢用户的可能;但同样很多时候,用户并不需要引导
- 前言今天我看了一下自己的文件夹,发现了自己写了许多似乎很无聊的代码。于是乎,一个想法油然而生:“生活已经很无聊了,不如再无聊一点叭”。说干就
- 本文实例为大家分享了python使用matplotlib画柱状图、散点图的具体代码,供大家参考,具体内容如下柱状图(plt.bar)代码与注
- 在MySQL中,对于索引的使用并是一直都采用正确的决定。简单表的示例:CREATE TABLE `r2` (ID` int(11) DEFA
- 在opencv中,特征检测、描述、匹配都有集成的函数。vector<DMatch> bestMatches;用来存储得到的匹配点
- 当我们在写程序的时候,我们需要通过测试来验证程序是否出错或者存在问题,但是,编写大量的测试来确保程序的每个细节都没问题会显得很繁琐。在Pyt
- 一、I/O模型IO在计算机中指Input/Output,也就是输入和输出。由于程序和运行时数据是在内存中驻留,由CPU这个超快的计算核心来执
- 本文实例讲述了python实现通过队列完成进程间的多任务功能。分享给大家供大家参考,具体如下:1.通过队列完成进程间的多任务import m
- PHP asXML()函数实例格式化 XML(版本 1.0)中的 SimpleXML 对象的数据:<?php $note=<&l
- 女朋友是一个软件测试人员,在工作中经常会遇到需要录屏记录自己操作,方便后续开发同学定位。因为录屏软件动不动就开始收费,所以她经常更换录屏软件
- pycharm里边安装不上d2l包。按以下步骤操作即可成功解决。1、首先查看现在pycharm所在的环境File—>