在上文的最佳化中,對每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的記憶體的方法的詳細內容。更多資訊請關注PHP中文網其他相關文章!