谈谈如何手动释放Python的内存
在上篇博客中,提到了对一个脚本进行的多次优化。当时以为已经优化得差不多了,但是当测试人员测试时,我才发现,踩到了Python的一个大坑。
在上文的优化中,对每500个用户,会进行一些计算并记录结果在磁盘文件中。原本以为这么做,这些结果就在磁盘文件中了,而不会再继续占用内存;但实际上,Python的大坑就是Python不会自动清理这些内存。这是由其本身实现决定的。具体原因网上多有文章介绍,这里就不copy了。
本篇博客将贴一个笔者的实验脚本,用以说明Python确实存在这么一个不释放内存的现象,另外也提出一个解决方案,即:先del,再显式调用gc.collect().脚本和具体效果见下。
实验环境一:Win7,Python2.7
fromtimeimportsleep,time importgc defmem(way=1): printtime() foriinrange(10000000): ifway==1: pass else:#way2,3 deli printtime() ifway==1orway==2: pass else:#way3 gc.collect() printtime() if__name__=="__main__": print"Testway1:justpass" mem(way=1) sleep(20) print"Testway2:justdel" mem(way=2) sleep(20) print"Testway3:del,andthengc.collect()" mem(way=3) sleep(20)
运行结果如下:
Testway1:justpass 1426688589.47 1426688590.25 1426688590.25 Testway2:justdel 1426688610.25 1426688611.05 1426688611.05 Testway3:del,andthengc.collect() 1426688631.05 1426688631.85 1426688631.95
对于way1和way2,结果是完全一样的,程序内存消耗峰值是326772KB,在sleep20秒时,内存实时消耗是244820KB;
对于way3,程序内存消耗峰值同上,但是sleep时内存实时消耗就只有6336KB了。
实验环境二:Ubuntu14.10,Python2.7.3
运行结果:
Testway1:justpass 1426689577.46 1426689579.41 1426689579.41 Testway2:justdel 1426689599.43 1426689601.1 1426689601.1 Testway3:del,andthengc.collect() 1426689621.12 1426689622.8 1426689623.11
ubuntu@my_machine:~$ps-aux|greptest_mem Warning:badpssyntax,perhapsabogus'-'?Seehttp://procps.sf.net/faq.html ubuntu912210.06.0270916245564pts/1S+14:390:03pythontest_mem.py ubuntu91340.00.08104924pts/2S+14:400:00grep--color=autotest_mem ubuntu@my_machine:~$ps-aux|greptest_mem Warning:badpssyntax,perhapsabogus'-'?Seehttp://procps.sf.net/faq.html ubuntu912210.06.0270916245564pts/1S+14:390:03pythontest_mem.py ubuntu91340.00.08104924pts/2S+14:400:00grep--color=autotest_mem ubuntu@my_machine:~$ps-aux|greptest_mem Warning:badpssyntax,perhapsabogus'-'?Seehttp://procps.sf.net/faq.html ubuntu912211.60.1309565608pts/1S+14:390:05pythontest_mem.py
结论:
以上说明,当调用del时,其实Python并不会真正release内存,而是将其继续放在其内存池中;只有在显式调用gc.collect()时,才会真正release内存。
进一步:
其实回到上一篇博客的脚本中,也让其引入gc.collect(),然后写个监控脚本监测内存消耗情况:
while((1));dops-aux|sort-n-k5,6|grepmy_script;free;sleep5;done
结果发现:内存并不会在每500个用户一组执行完后恢复,而是一直持续消耗到仅存约70MB时,gc才好像起作用。本环境中,机器使用的是Cloudinstance,总内存2G,可用内存约为1G,本脚本内存常用消耗是900M-1G。换句话说,对于这个脚本来说,gc并没有立即起作用,而是在系统可用内存从1-1.2G下降到只剩70M左右时,gc才开始发挥作用。这点确实比较奇怪,不知道和该脚本是在Thread中使用的gc.collect()是否有关,或者是gc发挥作用原本就不是可控的。笔者尚未做相关实验,可能在下篇博客中继续探讨。
但是,可以肯定的是,若不使用gc.collect(),原脚本将会将系统内存耗尽而被杀死。这一点从syslog中可以明显看出。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。