python的内存管理和垃圾回收机制,Python 内存溢出

  python的内存管理和垃圾回收机制,Python 内存溢出

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

  发布时间:2020-10-30 23:08:34

  来源:易俗云

  阅读:92

  作者:利亚

  本文将详细解释Python内存泄漏和内存溢出的解决方案。文章内容质量很高,边肖分享给大家,供参考。希望你看完这篇文章能有所了解。

  首先,内存泄漏

  和Java程序一样,Python本身也有垃圾回收的功能,但是也造成了内存泄漏的问题。

  对于一个用python实现的长时间运行的后台服务进程,如果内存一直增长,很可能存在“内存泄漏”。

  1.内存泄漏的原因

  对于python这种支持垃圾回收的语言来说,怎么还会有内存泄漏呢?总结起来有三个原因:C语言开发的底层模块发生了内存泄漏。

  代码使用一个全局列表、dict或者其他容器,不停地在这些容器中插入对象,用完后忘记删除回收。

  代码中存在“引用循环”,循环引用的对象定义了__del__方法,所以会出现内存泄漏。

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

  gc模块最常用的方法是gc.collect()方法,用来对循环引用的对象进行垃圾收集。

  如果我们在类中重载__del__方法。__del__方法定义了用del语句删除对象时除释放内存空间以外的操作。

  一般来说,在使用del语句时,解释器会首先查看要删除的对象的引用计数。如果为0,它将释放内存并执行del方法。

  这里首先说明,del语句出现时,其引用计数不为0(因为循环引用的存在),所以解释器不释放内存;

  再者,在执行collect方法时,要清除循环引用产生的无效引用计数,以达到del的目的。对于这两个圆形参照物,

  Python无法判断调用他们的del方法时是否会用到对方对象。比如b._a,也就是A,在做b.del()的时候可能会用到。如果A在那之前已经发布了,那就完全GG了。

  为了避免这种情况,collect方法在默认情况下不收集用del方法重载的循环引用对象,它们的状态将从不可到达变为不可收集。因为是不可收集的,自然不会被collect处理,所以进入了垃圾列表。

  2.内存泄漏的诊断思路

  无论是哪种内存泄露,最终的表现都是一些python对象在不断的增长;因此,首先要做的就是找到这些例外的对象。

  3.诊断步骤

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

  gc模块是Python的垃圾收集器模块,gc使用标签清除算法来收集垃圾。

  Objgraph是一个诊断内存问题的工具。1.在维修程序的循环逻辑中,选择一个诊断点。

  2.在诊断点,插入以下诊断语句

  导入gc

  导入对象图

  # # #强制垃圾收集

  gc.collect()

  # # #打印出对象数量最多的50种信息。

  obj graph . show _ most _ common _ types(限制=50)

  4.检查统计信息以发现异常对象。

  运行诊断语句的服务程序,并将屏幕上打印的统计数据重定向至日志。运行一段时间后,可以分析日志,看看哪些对象在不断增长。

  例如,结果可能是:

  多线程程序以多个线程作为生产者,一个线程作为消费者,通过向异步队列发送元组对象来进行通信。

  因为消费者的处理速度跟不上生产者,没有同步,异步队列中的对象越来越多。

  第二,内存溢出

  1.内存溢出导致加载到内存中的数据量过大,比如一次从数据库中取出太多的数据。

  集合中有对对象的引用,使用后没有清空,导致堆积,JVM无法回收。

  代码中存在无限循环,或者循环导致的重复对象实体太多。

  使用第三方软件中的错误

  启动参数记忆值设置太小。

  2.内存溢出的解决方案

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

  其次,检查错误日志,查看在“OutOfMemory”错误之前是否有其他异常或错误。

  第三步是遍历并分析代码,找出可能发生内存溢出的地方。

  重点关注以下几点:检查是否存在获取数据库查询中所有数据的查询。一般来说,如果一次取100,000条记录到内存中,可能会导致内存溢出。这个问题是隐藏的。在上线之前,数据库里的数据比较少,不容易出问题。上线后数据库中数据较多,一次查询就可能造成内存溢出。因此,数据库查询应该尽可能分页。

  检查代码中是否有无限循环或递归调用。

  检查是否存在重复生成新对象实体的大循环。

  检查列表、地图等集合对象使用后是否未清除。像List和MAP这样的集合对象总是有对对象的引用,所以这些对象不能被GC回收。

  步骤4:使用内存查看工具动态查看内存使用情况。

  第三,内存泄漏和内存溢出的区别

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

  内存泄漏是指一个内存空间被应用于JVM,但在使用后没有被释放。因为没有释放,所以加载时这个内存区域的其他类不能应用。

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

  值得注意的是,内存泄漏最终会导致内存溢出。很容易理解大量记忆丢失。最后当然是内存不够了。

  以上就是Python对内存泄漏和内存溢出的解决方案。希望以上能对你有所帮助,你能学到更多的知识。如果你觉得文章不错,可以分享给更多人看。

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: