2011-02-09 142 views
3

我有一個用python 2.6編寫的程序,它創建了大量的短期實例(這是一個典型的生產者 - 消費者問題)。我注意到,top和pmap報告的內存使用量在創建這些實例時似乎會增加,並且永遠不會回落。我擔心我使用的一些python模塊可能會泄漏內存,所以我仔細隔離了代碼中的問題。然後,我儘可能以儘可能簡短的方式重現它。我想出了這個:Python 2.6似乎GC清理對象,但內存不釋放

class LeaksMemory(list): 
    timesDelCalled = 0 

    def __del__(self): 
     LeaksMemory.timesDelCalled +=1 


def leakSomeMemory(): 
    l = [] 
    for i in range(0,500000): 
     ml = LeaksMemory() 
     ml.append(float(i)) 
     ml.append(float(i*2)) 
     ml.append(float(i*3)) 
     l.append(ml) 

import gc 
import os 


leakSomeMemory() 

print("__del__ was called " + str(LeaksMemory.timesDelCalled) + " times") 
print(str(gc.collect()) +" objects collected") 
print("__del__ was called " + str(LeaksMemory.timesDelCalled) + " times") 
print(str(os.getpid()) + " : check memory usage with pmap or top") 

如果你運行這個的東西,如「python2.6的-i memoryleak.py」,它會中止,您可以使用pmap -x PID檢查內存使用情況。我添加了del方法,所以我可以驗證GC是否發生。這在我的實際程序中並不存在,似乎沒有任何功能上的差異。每次調用leakSomeMemory()都會增加此程序消耗的內存量。我擔心我會犯一些簡單的錯誤,並且引用會被意外保存,但無法識別。

+0

如果等待一段時間,並在內存消耗回去了嗎?我的理解是,Python從池中分配出來,所以如果它必須擴大池,它可能不會在將內存釋放回池之後立即收縮。 – 2011-02-09 19:15:35

回答

8

Python將釋放對象,但不會立即將內存釋放回操作系統。相反,它將在相同的解釋器中重複使用相同的分段以用於將來的分配。

這裏有一個博客帖子有關的問題:http://effbot.org/pyfaq/why-doesnt-python-release-the-memory-when-i-delete-a-large-object.htm

更新:我測試了這個自己使用Python 2.6.4,並沒有注意到在內存使用量持續增加。一些調用leakSomeMemory()導致Python進程的內存佔用增加,並且一些使得它再次減少。所以這一切都取決於分配器如何重新使用內存。

4

根據Alex Martelli

「到 唯一真正可靠的方式確保一個大的內存,但臨時使用 做了所有的資源返回 系統當它這樣做,是有 使用發生在子進程中,其中 做需要內存的工作,然後 終止。「

因此,在您的情況下,聽起來像使用multiprocessing模塊在單獨的進程中運行短期功能以確保在進程完成時返回資源是有意義的。

import multiprocessing as mp 

def NOT_leakSomeMemory(): 
    # do stuff 
    return result 


if __name__=='__main__': 
    pool = mp.Pool() 
    results=pool.map(NOT_leakSomeMemory, range(500000)) 

有關如何使用多設置的東西了,看到Doug Hellman's tutorial更多的想法: