谈谈如何手动释放Python的内存


Posted in Python onDecember 17, 2016

在上篇博客中,提到了对一个脚本进行的多次优化。当时以为已经优化得差不多了,但是当测试人员测试时,我才发现,踩到了Python的一个大坑。

在上文的优化中,对每500个用户,会进行一些计算并记录结果在磁盘文件中。原本以为这么做,这些结果就在磁盘文件中了,而不会再继续占用内存;但实际上,Python的大坑就是Python不会自动清理这些内存。这是由其本身实现决定的。具体原因网上多有文章介绍,这里就不copy了。

本篇博客将贴一个笔者的实验脚本,用以说明Python确实存在这么一个不释放内存的现象,另外也提出一个解决方案,即:先del,再显式调用gc.collect(). 脚本和具体效果见下。

实验环境一:Win 7, Python 2.7

from time import sleep, time 
import gc 
 
def mem(way=1): 
 print time() 
 for i in range(10000000): 
  if way == 1: 
   pass 
  else: # way 2, 3 
   del i 
    
 print time() 
 if way == 1 or way == 2: 
  pass 
 else: # way 3 
  gc.collect() 
 print time() 
   
if __name__ == "__main__": 
 print "Test way 1: just pass" 
 mem(way=1) 
 sleep(20) 
 print "Test way 2: just del" 
 mem(way=2) 
 sleep(20) 
 print "Test way 3: del, and then gc.collect()" 
 mem(way=3) 
 sleep(20)

运行结果如下:

Test way 1: just pass 
1426688589.47 
1426688590.25 
1426688590.25 
Test way 2: just del 
1426688610.25 
1426688611.05 
1426688611.05 
Test way 3: del, and then gc.collect() 
1426688631.05 
1426688631.85 
1426688631.95

对于way 1和way 2,结果是完全一样的,程序内存消耗峰值是326772KB,在sleep 20秒时,内存实时消耗是244820KB;

对于way 3,程序内存消耗峰值同上,但是sleep时内存实时消耗就只有6336KB了。

实验环境二: Ubuntu 14.10, Python 2.7.3

运行结果:

Test way 1: just pass 
1426689577.46 
1426689579.41 
1426689579.41 
Test way 2: just del 
1426689599.43 
1426689601.1 
1426689601.1 
Test way 3: del, and then gc.collect() 
1426689621.12 
1426689622.8 
1426689623.11
ubuntu@my_machine:~$ ps -aux | grep test_mem 
Warning: bad ps syntax, perhaps a bogus '-'? See http://procps.sf.net/faq.html 
ubuntu 9122 10.0 6.0 270916 245564 pts/1 S+ 14:39 0:03 python test_mem.py 
ubuntu 9134 0.0 0.0 8104 924 pts/2 S+ 14:40 0:00 grep --color=auto test_mem 
ubuntu@my_machine:~$ ps -aux | grep test_mem 
Warning: bad ps syntax, perhaps a bogus '-'? See http://procps.sf.net/faq.html 
ubuntu 9122 10.0 6.0 270916 245564 pts/1 S+ 14:39 0:03 python test_mem.py 
ubuntu 9134 0.0 0.0 8104 924 pts/2 S+ 14:40 0:00 grep --color=auto test_mem 
ubuntu@my_machine:~$ ps -aux | grep test_mem 
Warning: bad ps syntax, perhaps a bogus '-'? See http://procps.sf.net/faq.html 
ubuntu 9122 11.6 0.1 30956 5608 pts/1 S+ 14:39 0:05 python test_mem.py

结论:

以上说明,当调用del时,其实Python并不会真正release内存,而是将其继续放在其内存池中;只有在显式调用gc.collect()时,才会真正release内存。

进一步:

其实回到上一篇博客的脚本中,也让其引入gc.collect(),然后写个监控脚本监测内存消耗情况:

while ((1)); do ps -aux | sort -n -k5,6 | grep my_script; free; sleep 5; done

结果发现:内存并不会在每500个用户一组执行完后恢复,而是一直持续消耗到仅存约70MB时,gc才好像起作用。本环境中,机器使用的是Cloud instance,总内存2G,可用内存约为1G,本脚本内存常用消耗是900M - 1G。换句话说,对于这个脚本来说,gc并没有立即起作用,而是在系统可用内存从1 - 1.2G下降到只剩70M左右时,gc才开始发挥作用。这点确实比较奇怪,不知道和该脚本是在Thread中使用的gc.collect()是否有关,或者是gc发挥作用原本就不是可控的。笔者尚未做相关实验,可能在下篇博客中继续探讨。

但是,可以肯定的是,若不使用gc.collect(), 原脚本将会将系统内存耗尽而被杀死。这一点从syslog中可以明显看出。

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

Python 相关文章推荐
详解Python3.1版本带来的核心变化
Apr 07 Python
将TensorFlow的模型网络导出为单个文件的方法
Apr 23 Python
Python用于学习重要算法的模块pygorithm实例浅析
Aug 16 Python
Django中的ajax请求
Oct 19 Python
selenium+python环境配置教程详解
May 28 Python
对python特殊函数 __call__()的使用详解
Jul 02 Python
介绍一款python类型检查工具pyright(推荐)
Jul 03 Python
4行Python代码生成图像验证码(2种)
Apr 07 Python
Python操作Excel把数据分给sheet
May 20 Python
python求numpy中array按列非零元素的平均值案例
Jun 08 Python
完美解决Pycharm中matplotlib画图中文乱码问题
Jan 11 Python
教你如何用python开发一款数字推盘小游戏
Apr 14 Python
深入理解NumPy简明教程---数组3(组合)
Dec 17 #Python
深入理解NumPy简明教程---数组2
Dec 17 #Python
深入理解NumPy简明教程---数组1
Dec 17 #Python
Python脚本获取操作系统版本信息
Dec 17 #Python
详解python中xlrd包的安装与处理Excel表格
Dec 16 #Python
详解python开发环境搭建
Dec 16 #Python
python制作爬虫爬取京东商品评论教程
Dec 16 #Python
You might like
PHP如何编写易读的代码
2007/07/10 PHP
PHP ? EasyUI DataGrid 资料存的方式介绍
2012/11/07 PHP
php 表单提交大量数据发生丢失的解决方法
2014/03/03 PHP
Thinkphp 框架基础之入口文件功能、定义与用法分析
2020/04/27 PHP
JS 自定义带默认值的函数
2011/07/21 Javascript
节点的插入之append()和appendTo()的用法介绍
2014/01/13 Javascript
我的Node.js学习之路(二)NPM模块管理
2014/07/06 Javascript
关于javascript中dataset的问题小结
2015/11/16 Javascript
javascript跨域请求包装函数与用法示例
2016/11/03 Javascript
Javascript使用function创建类的两种方法(推荐)
2016/11/19 Javascript
VUE JS 使用组件实现双向绑定的示例代码
2017/01/10 Javascript
js css3实现图片拖拽效果
2017/03/04 Javascript
Extjs表单输入框异步校验的插件实现方法
2017/03/20 Javascript
js 用于检测类数组对象的函数方法
2017/05/02 Javascript
Three.js利用Detector.js插件如何实现兼容性检测详解
2017/09/26 Javascript
详解处理bootstrap4不支持远程静态框问题
2018/07/20 Javascript
vue中子组件的methods中获取到props中的值方法
2018/08/27 Javascript
NodeJS有难度的面试题(能答对几个)
2019/10/09 NodeJs
JS实现打砖块游戏
2020/02/14 Javascript
ES5新增数组的实现方法
2020/05/12 Javascript
[02:21]DOTA2英雄基础教程 蝙蝠骑士
2013/12/16 DOTA
[36:02]DOTA2上海特级锦标赛D组小组赛#2 Liquid VS VP第一局
2016/02/28 DOTA
在Debian下配置Python+Django+Nginx+uWSGI+MySQL的教程
2015/04/25 Python
django实现分页的方法
2015/05/26 Python
Python统计文件中去重后uuid个数的方法
2015/07/30 Python
10分钟教你用Python实现微信自动回复功能
2018/11/28 Python
Python 抓取微信公众号账号信息的方法
2019/06/14 Python
利用python实现周期财务统计可视化
2019/08/25 Python
python 串口读取+存储+输出处理实例
2019/12/26 Python
css3 border-radius属性详解
2017/07/05 HTML / CSS
细说CSS3中的选择符
2008/10/17 HTML / CSS
CSS3 实用技巧:实现黑白图像效果示例代码
2013/07/11 HTML / CSS
canvas使用注意点总结
2013/07/19 HTML / CSS
recorder.js 基于Html5录音功能的实现
2020/05/26 HTML / CSS
忆童年!用Python实现愤怒的小鸟游戏
2021/06/07 Python
Windows Server 2016服务器用户管理及远程授权图文教程
2022/08/14 Servers