亚洲国产日韩欧美一区二区三区,精品亚洲国产成人av在线,国产99视频精品免视看7,99国产精品久久久久久久成人热,欧美日韩亚洲国产综合乱

談?wù)勅绾问謩?dòng)釋放Python的內(nèi)存

原創(chuàng) 2017-01-09 11:04:32 487
摘要:在上篇博客中,提到了對(duì)一個(gè)腳本進(jìn)行的多次優(yōu)化。當(dāng)時(shí)以為已經(jīng)優(yōu)化得差不多了,但是當(dāng)測(cè)試人員測(cè)試時(shí),我才發(fā)現(xiàn),踩到了Python的一個(gè)大坑。在上文的優(yōu)化中,對(duì)每500個(gè)用戶,會(huì)進(jìn)行一些計(jì)算并記錄結(jié)果在磁盤文件中。原本以為這么做,這些結(jié)果就在磁盤文件中了,而不會(huì)再繼續(xù)占用內(nèi)存;但實(shí)際上,Python的大坑就是Python不會(huì)自動(dòng)清理這些內(nèi)存。這是由其本身實(shí)現(xiàn)決定的。具體原因網(wǎng)上多有文章介紹,這里就不co

在上篇博客中,提到了對(duì)一個(gè)腳本進(jìn)行的多次優(yōu)化。當(dāng)時(shí)以為已經(jīng)優(yōu)化得差不多了,但是當(dāng)測(cè)試人員測(cè)試時(shí),我才發(fā)現(xiàn),踩到了Python的一個(gè)大坑。

在上文的優(yōu)化中,對(duì)每500個(gè)用戶,會(huì)進(jìn)行一些計(jì)算并記錄結(jié)果在磁盤文件中。原本以為這么做,這些結(jié)果就在磁盤文件中了,而不會(huì)再繼續(xù)占用內(nèi)存;但實(shí)際上,Python的大坑就是Python不會(huì)自動(dòng)清理這些內(nèi)存。這是由其本身實(shí)現(xiàn)決定的。具體原因網(wǎng)上多有文章介紹,這里就不copy了。

本篇博客將貼一個(gè)筆者的實(shí)驗(yàn)?zāi)_本,用以說明Python確實(shí)存在這么一個(gè)不釋放內(nèi)存的現(xiàn)象,另外也提出一個(gè)解決方案,即:先del,再顯式調(diào)用gc.collect(). 腳本和具體效果見下。

實(shí)驗(yàn)環(huán)境一: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)

運(yùn)行結(jié)果如下:

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

對(duì)于way 1和way 2,結(jié)果是完全一樣的,程序內(nèi)存消耗峰值是326772KB,在sleep 20秒時(shí),內(nèi)存實(shí)時(shí)消耗是244820KB;

對(duì)于way 3,程序內(nèi)存消耗峰值同上,但是sleep時(shí)內(nèi)存實(shí)時(shí)消耗就只有6336KB了。

實(shí)驗(yàn)環(huán)境二: Ubuntu 14.10, Python 2.7.3

運(yùn)行結(jié)果:

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

   

結(jié)論:

以上說明,當(dāng)調(diào)用del時(shí),其實(shí)Python并不會(huì)真正release內(nèi)存,而是將其繼續(xù)放在其內(nèi)存池中;只有在顯式調(diào)用gc.collect()時(shí),才會(huì)真正release內(nèi)存。

進(jìn)一步:

其實(shí)回到上一篇博客的腳本中,也讓其引入gc.collect(),然后寫個(gè)監(jiān)控腳本監(jiān)測(cè)內(nèi)存消耗情況:

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

結(jié)果發(fā)現(xiàn):內(nèi)存并不會(huì)在每500個(gè)用戶一組執(zhí)行完后恢復(fù),而是一直持續(xù)消耗到僅存約70MB時(shí),gc才好像起作用。本環(huán)境中,機(jī)器使用的是Cloud instance,總內(nèi)存2G,可用內(nèi)存約為1G,本腳本內(nèi)存常用消耗是900M - 1G。換句話說,對(duì)于這個(gè)腳本來說,gc并沒有立即起作用,而是在系統(tǒng)可用內(nèi)存從1 - 1.2G下降到只剩70M左右時(shí),gc才開始發(fā)揮作用。這點(diǎn)確實(shí)比較奇怪,不知道和該腳本是在Thread中使用的gc.collect()是否有關(guān),或者是gc發(fā)揮作用原本就不是可控的。筆者尚未做相關(guān)實(shí)驗(yàn),可能在下篇博客中繼續(xù)探討。

但是,可以肯定的是,若不使用gc.collect(), 原腳本將會(huì)將系統(tǒng)內(nèi)存耗盡而被殺死。這一點(diǎn)從syslog中可以明顯看出。

更多關(guān)于如何手動(dòng)釋放Python的內(nèi)存請(qǐng)關(guān)注PHP中文網(wǎng)(ipnx.cn)其他文章!

發(fā)佈手記

熱門詞條