谈谈如何手动释放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 相关文章推荐
python聊天程序实例代码分享
Nov 18 Python
Python开发常用的一些开源Package分享
Feb 14 Python
玩转python爬虫之爬取糗事百科段子
Feb 17 Python
python中set常用操作汇总
Jun 30 Python
pycharm 在windows上编辑代码用linux执行配置的方法
Oct 27 Python
python BlockingScheduler定时任务及其他方式的实现
Sep 19 Python
pytorch torch.expand和torch.repeat的区别详解
Nov 05 Python
python实现的多任务版udp聊天器功能案例
Nov 13 Python
python encrypt 实现AES加密的实例详解
Feb 20 Python
Python调用OpenCV实现图像平滑代码实例
Jun 19 Python
Python使用sys.exc_info()方法获取异常信息
Jul 23 Python
Python通过fnmatch模块实现文件名匹配
Sep 30 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 错误之引号中使用变量
2009/05/04 PHP
PHP中多维数组的foreach遍历示例
2014/06/13 PHP
PHP网页游戏学习之Xnova(ogame)源码解读(一)
2014/06/23 PHP
PHP常见字符串处理函数用法示例【转换,转义,截取,比较,查找,反转,切割】
2016/12/24 PHP
PHP静态成员变量和非静态成员变量详解
2017/02/14 PHP
Yii2实现UploadedFile上传文件示例
2017/02/15 PHP
用JSON做数据传输格式中的一些问题总结
2011/12/21 Javascript
P3P Header解决Cookie跨域的问题
2013/03/12 Javascript
js去空格技巧分别去字符串前后、左右空格
2013/10/21 Javascript
JQuery datepicker 用法详解
2015/12/25 Javascript
使用do...while的方法输入一个月中所有的周日(实例代码)
2016/07/22 Javascript
Javascript动画效果(3)
2016/10/11 Javascript
javascript图片预览和上传(兼容IE)
2017/03/15 Javascript
jQuery.ajax向后台传递数组问题的解决方法
2017/05/12 jQuery
Vue 中批量下载文件并打包的示例代码
2017/11/20 Javascript
关于ligerui子页面关闭后,父页面刷新,重新加载的方法
2019/09/27 Javascript
Vue.js实现大转盘抽奖总结及实现思路
2019/10/09 Javascript
在VUE中实现文件下载并判断状态的方法
2019/11/08 Javascript
Python中使用item()方法遍历字典的例子
2014/08/26 Python
使用Python脚本生成随机IP的简单方法
2015/07/30 Python
Django添加favicon.ico图标的示例代码
2018/08/07 Python
对pandas里的loc并列条件索引的实例讲解
2018/11/15 Python
Python绘制并保存指定大小图像的方法
2019/01/10 Python
python保存log日志,实现用log日志画图
2019/12/24 Python
PyQt5-QDateEdit的简单使用操作
2020/07/12 Python
python实现图片,视频人脸识别(dlib版)
2020/11/18 Python
pycharm 配置svn的图文教程(手把手教你)
2021/01/15 Python
Html5剪切板功能的实现代码
2018/06/29 HTML / CSS
css 如何让背景图片拉伸填充避免重复显示
2013/07/11 HTML / CSS
美国购买和销售礼品卡平台:Raise
2017/01/13 全球购物
Max&Co官网:意大利年轻女性时尚品牌
2017/05/16 全球购物
社区党总支书记先进事迹材料
2014/01/24 职场文书
跳蚤市场口号
2014/06/13 职场文书
出租房屋协议书
2014/09/14 职场文书
2016新年致辞
2015/08/01 职场文书
python爬取企查查企业信息之selenium自动模拟登录企查查
2021/04/08 Python