在上篇部落格中,提到了對乙個指令碼進行的多次優化。當時以為已經優化得差不多了,但是當測試人員測試時,我才發現,踩到了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
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
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
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記憶體。
進一步:
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中可以明顯看出。
如何手動釋放Linux記憶體的方法
當在linux下頻繁訪問檔案後,物理記憶體會很快被用光,當程式結束後,記憶體不會被正常釋放,而是一直作為caching。這個問題,貌似有不少人在問,不過都沒有看到有什麼很好解決的辦法。那麼我來談談這個問題。proc是乙個虛擬檔案系統,我們可以通過對它的讀寫操作做為與kernel實體間進行通訊的一種手...
linux 手動釋放記憶體
當在linux下 頻繁訪問檔案 或者 程式測試頻繁崩潰後,物理記憶體會很快被用光,當程式結束後,記憶體不會被正常釋放,而是一直作為caching 因此我們很有必要手動清理系統快取釋放記憶體。我們在清理快取前應該先 sync下 因為系統在操作的過程當中,會把你的操作到的檔案資料先儲存到buffer中去...
linux手動釋放記憶體
當在linux下頻繁訪問檔案後,物理記憶體會很快被用光,當程式結束後,記憶體不會被正常釋放,而是一直作為caching。這個問題,貌似有不少人在問,不過都沒有看到有什麼很好解決的辦法。那麼我來談談這個問題。proc是乙個虛擬檔案系統,可通過對它的讀寫操作做為與kernel實體間進行通訊的一種手段。也...