Python跑循环时内存泄露的解决方法


Posted in Python onJanuary 13, 2020

Python跑循环时内存泄露

今天在用Tensorflow跑回归做测试时,仅仅需要循环四千多次 (补充说一句,我在个人PC上跑的)。运行以后,我就吃饭去了。等我回来后,Console窗口直接亮红了!!!

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import tensorflow as tf
import matplotlib.font_manager as fm
myfont = fm.FontProperties(fname='C:/Windows/Fonts/simsun.ttc')
sess = tf.Session()

for j in range(0,4096):
  print('第' + str(j) + '次回归')
  ......

此处忘了截图,反正就是说Keras出现了什么什么错误。然后我就顺手重启了工程。

接着就瞪着屏幕,为什么跑一半出错了???

Python跑循环时内存泄露的解决方法

这个时候我发现电脑管家的小火箭好像有点‘暴躁',打开任务管理器一看,果然。。。

Python跑循环时内存泄露的解决方法

Python占用内存都快两个G了,但是平时跑没有占用这么多呀。我就猜想是不是因为跑循环,内存没有释放,导致最后溢出,然后code就崩了。

抱着猜想的心态等了一分钟,然后。。

Python跑循环时内存泄露的解决方法

WTF 飙到两千三百多兆的占用了。结论很明显了,就是没有释放内存!!!
这让我想起来一个月前我在集群上并行GPU跑LSTM时,出现了Out of memory,

Python跑循环时内存泄露的解决方法

这是2080ti呀,足足十一个G的内存,虽然当时我就用了一块显卡,但也不至于溢出吧。当时没有想到是这个问题,现在回想一下十有八九就是没有释放内存。

至于为什么没有释放内存,那就要从下面这个人出生的时候说起了—>

Python跑循环时内存泄露的解决方法

还记得那是一个月黑风高夜晚,天空电闪雷鸣。。。。。。
hhh,开个玩笑,这个人是Python之父,不过我觉得接下来我要说的Python垃圾收集机制或多或少和他有一定的关系。

Python垃圾收集机制

现在的高级语言如java,c#等,都采用了垃圾收集机制,而不再是c,c++里用户自己管理维护内存的方式。自己管理内存极其自由,可以任意申请内存,但如同一把双刃剑,为大量内存泄露,悬空指针等bug埋下隐患。

对于一个字符串、列表、类甚至数值都是对象,且定位简单易用的语言,自然不会让用户去处理如何分配回收内存的问题。

python里也同java一样采用了垃圾收集机制,不过不一样的是:

python采用的是引用计数机制为主,标记-清除和分代收集两种机制为辅的策略。

Python中的内存管理过程非常简单。Python通过保持对每个对象在程序中的引用计数来处理其对象,这意味着每个对象存储在程序中被引用的次数。此计数随程序运行时更新,并且当计数为零时,这意味着程序不再可访问该计数。因此,解释器可以回收和释放该对象的内存。

class User(object):
  def __del__(self):
    print("No reference left for {}".format(self))
user1 = User()
user2 = user1
user3 = user1

在此示例中,我们制作了一个类和3个引用变量指向同一对象。让我们将其可视化:

Python跑循环时内存泄露的解决方法

现在,让变量user1,user2和user3指向None而不是User实例。

>>> user1 = None
>>> user2 = None
>>> user3 = None
No reference left for <__main__.User object at 0x212bee9d9>

通过以上代码,引用已更改为:

Python跑循环时内存泄露的解决方法

将最后一个变量分配user3给后None,该对象将被垃圾回收,这将调用该__del__函数。
从根本上讲,每当引用对象时,Python对象的引用计数都会增加,而在取消引用对象时,Python的引用计数会减少。如果对象的引用计数为0,则将释放该对象的内存。您程序的代码无法禁用Python的引用计数。

python跑循环为什么没有释放内存

有些人认为,引用计数是A poor man's garbage collector 。很大一部分原因是它存在一些缺点,其中就包括无法检测到循环应用。
如果在循环引用中的对象定义了__del__函数,那么在循环引用中Python解释器无法判断析构对象的顺序,因此就不做处理,python gc不能进行回收。

解决办法

在提出解决问题之前,我们要先找到问题。因为我这个Code需要画图,然后保存到本地。我就想是不是画的图导致占用过多内存。

F_max = max(y_result)
plt.figure(figsize=(15, 5)) 
plt.subplot(131)
plt.scatter(Yp_data, Yt_data, alpha=0.8)
plt.title(u'回归前结果',fontproperties=myfont)
plt.plot([0,F_max], [0,F_max], color = 'r')
  
plt.subplot(132)
plt.scatter(y_result, Yt_data, alpha=0.8)
plt.title(u'回归后结果',fontproperties=myfont)
plt.plot([0,F_max], [0,F_max], color = 'r')
  
plt.subplot(133)
plt.plot(loss_vec, 'k-')
plt.title('loss per Generation')
plt.xlabel('Generation')
plt.ylabel('Loss')
plt.savefig('D:/lwt/py/Regression/figure/{} .png'.format(_type), dpi=100)
plt.show()

有想法你就要去做是吧,然后我就加了两行代码。

plt.close('all')
plt.clf()

这两句是用来清除内存中的图像和清理掉 axes,并且为了尽可能的减少内存占用,把plt.show()都删除了
然后运行Code,打开任务管理器,测试是否管用。
貌似python占用的内存是没有之前上升的那么快了,不知道是不是心理作用hh。反正效果不明显,看来得从别的地方下手了。
排除掉这个可能,那就是回收机制的锅了。既然你不主动,那我就主动点咯(猿式阴笑嘿嘿)。

for x in list(locals().keys())[:]:
  del locals()[x]
gc.collect()

for循环就不要过多解释了,先说del 语句的用法

del obj_name

del是一个Python关键字。而且,obj_name 可以是变量,用户定义的对象,列表,列表中的项,字典等。可以用来删除用户定义的对象;删除变量,列表和字典;从列表中删除项目和切片;从字典中删除键等等。具体用法大家可以查找相关文档了解。

gc是python的垃圾回收器接口,gc.collect(generation=2)若被调用时不包含参数,则启动完全的垃圾回收。可选的参数 generation 可以是一个整数,指明需要回收哪一代(从 0 到 2 )的垃圾。当参数 generation 无效时,会引发 ValueError 异常。返回发现的不可达对象的数目。每当运行完整收集或最高代 (2) 收集时,为多个内置类型所维护的空闲列表会被清空。 由于特定类型特别是 float 的实现,在某些空闲列表中并非所有项都会被释放。

实测,有明显的效果,内存占用上升的速度明显减小了,不过总体还是承上升的趋势。相比之前,好太多了有没有。
方法总比困难多,解决内存泄漏也还有其他的办法。我们还可以用objgraph、weakref等工具来分析并解决内存泄露、循环引用问题。实在不行,还有一个超级硬核的办法,自己动手写一个腾讯电脑管家小火箭的脚本,时不时的让它上上天(腾讯记得打钱啊啊啊)。哈哈哈

在任何环境,不管是服务器,客户端,内存泄露都是非常严重的事情。如果是线上服务器,那么一定得有监控,如果发现内存使用率超过设置的阈值则立即报警,尽早发现些许还有救。

新的问题

不要强行收集垃圾太多次。这是因为,即使要释放内存,仍然需要花费时间来评估对象是否符合垃圾收集条件。我在实测中的确发现运行速度有些下降。
还有就是他会把全局的变量都删了,以至于出现nppd等导入的包都not defined。我的建议是把循环写到函数里,做到只对某个函数起作用。

笔者作为一个学生也是刚接触python不久,如有不对的地方还请指正,谢谢~

 以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Django中模版的子目录与include标签的使用方法
Jul 16 Python
在Python程序中操作MySQL的基本方法
Jul 29 Python
Python的Scrapy爬虫框架简单学习笔记
Jan 20 Python
Python编写登陆接口的方法
Jul 10 Python
使用Anaconda3建立虚拟独立的python2.7环境方法
Jun 11 Python
Python列表推导式与生成器用法分析
Aug 02 Python
python3判断url链接是否为404的方法
Aug 10 Python
python 实现将txt文件多行合并为一行并将中间的空格去掉方法
Dec 20 Python
浅谈python str.format与制表符\t关于中文对齐的细节问题
Jan 14 Python
Python神奇的内置函数locals的实例讲解
Feb 22 Python
关于Python作用域自学总结
Jun 10 Python
Python利用Pillow(PIL)库实现验证码图片的全过程
Oct 04 Python
PyTorch使用cpu加载模型运算方式
Jan 13 #Python
Python如何读取文件中图片格式
Jan 13 #Python
详解python破解zip文件密码的方法
Jan 13 #Python
PyTorch 随机数生成占用 CPU 过高的解决方法
Jan 13 #Python
python批量处理txt文件的实例代码
Jan 13 #Python
Python hashlib常见摘要算法详解
Jan 13 #Python
Pytorch释放显存占用方式
Jan 13 #Python
You might like
ADODB类使用
2006/11/25 PHP
浅析php中三个等号(===)和两个等号(==)的区别
2013/08/06 PHP
PHP命名空间namespace用法实例分析
2016/09/27 PHP
PHP简单读取xml文件的方法示例
2017/04/20 PHP
javascript smipleChart 简单图标类
2011/01/12 Javascript
TextArea设置MaxLength属性最大输入值的js代码
2012/12/21 Javascript
Jquery通过Ajax方式来提交Form表单的具体实现
2013/11/07 Javascript
JavaScript实现的一个计算数字步数的算法分享
2014/12/06 Javascript
跟我学习JScript的Bug与内存管理
2015/11/18 Javascript
js的form表单提交url传参数(包含+等特殊字符)的两种解决方法
2016/05/25 Javascript
jQuery Ajax和getJSON获取后台普通json数据和层级json数据用法分析
2016/06/08 Javascript
js传值后台中文出现乱码的解决方法
2016/06/30 Javascript
jQuery插件HighCharts绘制简单2D折线图效果示例【附demo源码】
2017/03/21 jQuery
js实现一个猜数字游戏
2017/03/31 Javascript
seajs实现强制刷新本地缓存的方法分析
2017/10/16 Javascript
详解TypeScript+Vue 插件 vue-class-component的使用总结
2019/02/18 Javascript
20个必会的JavaScript面试题(小结)
2019/07/02 Javascript
vue中使用vee-validator完成表单校验方案
2019/11/01 Javascript
Python中列表list以及list与数组array的相互转换实现方法
2017/09/22 Python
python机器学习库常用汇总
2017/11/15 Python
深入了解Python中pop和remove的使用方法
2018/01/09 Python
python列表,字典,元组简单用法示例
2019/07/11 Python
关于python的缩进规则的知识点详解
2020/06/22 Python
selenium自动化测试入门实战
2020/12/21 Python
深圳-东方伟业笔试部分
2015/02/11 面试题
英文版餐饮运营管理求职信
2013/11/06 职场文书
本科应届生求职信
2014/08/05 职场文书
2015年世界艾滋病日活动总结
2015/03/24 职场文书
被告答辩状范文
2015/05/22 职场文书
2015年图书馆个人工作总结
2015/05/26 职场文书
婚礼答谢词范文
2015/09/29 职场文书
2016大学生暑期三下乡心得体会
2016/01/23 职场文书
小学英语课教学反思
2016/02/15 职场文书
2016年小学“我们的节日·中秋节”活动总结
2016/04/05 职场文书
聊聊golang中多个defer的执行顺序
2021/05/08 Golang
nginx实现动静分离的方法示例
2021/11/07 Servers