Python跑循环时内存泄露的解决方法
作者:L_W_T_ 发布时间:2023-07-18 08:18:22
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占用内存都快两个G了,但是平时跑没有占用这么多呀。我就猜想是不是因为跑循环,内存没有释放,导致最后溢出,然后code就崩了。
抱着猜想的心态等了一分钟,然后。。
WTF 飙到两千三百多兆的占用了。结论很明显了,就是没有释放内存!!!
这让我想起来一个月前我在集群上并行GPU跑LSTM时,出现了Out of memory,
这是2080ti呀,足足十一个G的内存,虽然当时我就用了一块显卡,但也不至于溢出吧。当时没有想到是这个问题,现在回想一下十有八九就是没有释放内存。
至于为什么没有释放内存,那就要从下面这个人出生的时候说起了—>
还记得那是一个月黑风高夜晚,天空电闪雷鸣。。。。。。
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个引用变量指向同一对象。让我们将其可视化:
现在,让变量user1,user2和user3指向None而不是User实例。
>>> user1 = None
>>> user2 = None
>>> user3 = None
No reference left for <__main__.User object at 0x212bee9d9>
通过以上代码,引用已更改为:
将最后一个变量分配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等工具来分析并解决内存泄露、循环引用问题。实在不行,还有一个超级硬核的办法,自己动手写一个腾讯电脑管家小火箭的脚本,时不时的让它上上天(腾讯记得打钱啊啊啊)。哈哈哈
在任何环境,不管是服务器,客户端,内存泄露都是非常严重的事情。如果是线上服务器,那么一定得有监控,如果发现内存使用率超过设置的阈值则立即报警,尽早发现些许还有救。
新的问题
不要强行收集垃圾太多次。这是因为,即使要释放内存,仍然需要花费时间来评估对象是否符合垃圾收集条件。我在实测中的确发现运行速度有些下降。
还有就是他会把全局的变量都删了,以至于出现np
和pd
等导入的包都not defined。我的建议是把循环写到函数里,做到只对某个函数起作用。
笔者作为一个学生也是刚接触python不久,如有不对的地方还请指正,谢谢~
来源:https://blog.csdn.net/L_W_T_/article/details/103916415
猜你喜欢
- python2.7中 集成了json的处理(simplejson),但在实际应用中,从mysql查询出来的数据,通常有日期格式,这时候,会报
- 这篇文章主要介绍了Python list运算操作代码实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需
- 首先导入包含apriori算法的mlxtend库,pip install mlxtend调用apriori进行关联规则分析,具体代码如下,其
- FSO中除了可以对驱动器、文件夹的操作以外,功能最强大的就是对文件的操作了。它可以用来记数、内容管理、搜索还可生成动态HTML页面等等。一、
- 任何位置都能明确“我在哪里?这里有什么?从这里能去哪里?” 小时候,童话故事都告诉我们,迷路可不是一件好事。那会伴随着困惑、沮丧、
- 译者按:我们时常能看到不同JavaScript库/框架之间的各种比较,但这次 YUI3 架构师和 jQuery 之父的直接对话却非常难得,也
- Pandas库中有iloc和loc以及ix可以用来索引数据,抽取数据。但是方法一多也容易造成混淆。下面将一一来结合代码说清其中的区别。1.
- 工作中遇到一个问题,两个字符串匹配,要求:每个字符串中最多含有一个*,?可以无限多个*代表一个任意长度的字符串,而?则代表一个字符要求可以提
- 前言:大家在写代码的时候,经常会使用print打印日志方便排查问题,然而print的问题就是太过简单,缺少时间、日志级别等格式化信息。Pyt
- 直接上代码:1. 第一种情况如果没有select{}, main 主线程不会等待coroutine运行,导致coroutine得不到机会运行
- 目录vuex持久化总结vuex持久化vuex:刷新浏览器,vuex中的state会重新变为初始状态解决办法:使用vuex-persisted
- 一、高级异常回顾异常相关的语句:try-except:用来捕获异常的通知try-finally:用来做一定要做的事reise:用来发生异常通
- 前言本文使用 cpu 版本的 TensorFlow 2.4 ,分别搭建单层 Bi-LSTM 模型和多层 Bi-LSTM 模型完成文本分类任务
- 复制是将主数据库的DDL和DML操作通过二进制日志传到从库上,然后再从库重做,从而使得从库和主库保持数据的同步。MySQL可以从一台主库同时
- jupyter介绍jupyter的全称为Jupyter Notebook,之前一度被称为(IPython notebook),是一种交互式的
- 有时候我们用的一些pdf资料是没有目录的,这样找寻我们想到的东西比较麻烦。本篇文章就为大家带来python来生成pdf目录书签的方法。首先,
- 毫无疑问,我们生活在编辑器的最好年代,Vim是仅在Vi之下的神级编辑器,而脱胎于Vim的NeoVim则是这个时代最好的编辑器,没有之一。异步
- Config:服务端连接Git配置,代码如下所示:1、导入依赖<dependencies> <d
- 我就废话不多说了,大家还是直接看代码吧~#coding=utf-8import cv2import numpy as npimg=cv2.i
- 1.beautifulsoup4库安装第一步:在控制台输入如下命令,安 * eautifulsoup4库。pip install beauti