2012-09-14 24 views
17

在很多情況下,你確信你絕對不會再使用該列表,希望內存應該放開,現在如何在Python列表中立即釋放已用內存?

a = [11,22,34,567,9999] 
del a 

我不知道它是否真的釋放內存,你可以使用

del a[:] 

實際上刪除列表中的所有元素a。

所以最好的發佈方式是這樣嗎?

def realse_list(a): 
    del a[:] 
    del a 

不太確定。需要您的意見。

btw,如何元組和集?

+9

除非你正在處理大量的數據,並且實際上得到了一個MemoryError異常,不用擔心內存管理。 – monkut

回答

19
def release_list(a): 
    del a[:] 
    del a 

不要永遠做到這一點。 Python會自動釋放所有不再被引用的對象,所以一個簡單的del a可以確保列表的內存將被釋放,如果該列表在其他地方沒有被引用的話。如果是這樣的話,那麼單個列表項目也將被釋放(以及僅從它們引用的任何對象,等等),除非某些單個項目還被引用。

這意味着只有時候del a[:]; del a將釋放超過del a自身是當被引用其他地方的列表。這是恰恰是當你不應該被清空列表:別人仍在使用它!

基本上,你不應該考慮管理內存塊。相反,請考慮管理對象的引用。在所有Python代碼的99%中,Python在您最後一次需要它之後立即清理您不需要的所有內容,並且沒有任何問題。每次函數完成該函數中的所有局部變量「死亡」時,如果它們指向的是其他地方未引用的對象,則它們將被刪除,並且會級聯到這些對象中包含的所有內容。

你唯一需要考慮的就是當你有一個大對象(比如說一個巨大的列表)時,你對它做了一些事情,然後開始一個長時間運行(或者說是內存密集型)的子計算,其中大對象不是子計算所需的。因爲您有對它的引用,所以在子計算完成並且返回之前,大對象不會被釋放。在那種情況下(和那種情況下),你可以明確地del您參考大對象開始分計算之前,這樣大的物體可以更早釋放(如果沒有其他人是使用它;如果呼叫者在向您來電確實還用得着你返回後傳遞的對象,你會非常高興,它並沒有得到釋放)。

+0

如果** **是一個成員變量(一個大的變量),我知道我不會再使用它,那麼這算作「引用變量」嗎? 該方案很簡單:我有一個處理大列表_when_needed_的對象。在調用某個方法後,處理** a **列表並緩存結果。在這種情況下,我知道我不再需要** a **了。 – hsgubert

+1

@hsgubert如果'a'是某個對象(成員變量)的一個屬性,那麼它就被該對象的一部分引用(假設該對象本身在某處引用)。但是如果你知道你不再需要它,並且你處於同一個類的一個方法中,你可以用'del self.a'去除它。如果你不是那種類的方法,不要惹它。良好的設計幾乎總是讓每個班級負責管理自己的屬性;如果該程序的其他部分可以隨機決定該對象不再需要其中一個屬性,那麼很難理解該類。 – Ben

4

正如@monkut所指出的那樣,在大多數情況下,你可能不應該過分擔心內存管理。如果你有你確定你與現在做,也不會走出當前函數的範圍了一段時間,但一個巨大的列表:

del a簡單地刪除名字a爲大量的記憶。如果其他功能或結構或任何其他參考仍然存在,它不會被刪除;如果此代碼僅對名稱爲a的該列表引用,並且您正在使用CPython,則引用計數器將立即釋放該內存。其他實現(PyPy,Jython,IronPython)可能不會馬上殺死它,因爲它們有不同的垃圾收集器。

正因爲如此,realse_list函數中的del a語句實際上並沒有做任何事情,因爲調用方仍然有一個引用!

del a[:]如您所見,將從列表中刪除元素,因此可能會消耗大部分內存使用量。

對於具有集合的類似行爲,您可以執行the_set.clear()

所有你可以用一個元組來做,因爲它們是不可改變的,它是del the_tuple,並且希望別人沒有對它的引用 - 但是你可能不應該擁有巨大的元組!

+1

通過討論弱引用,這個答案會更加完整。 – Marcin

1

如果您擔心內存管理和性能數據類型爲什麼不使用類似鏈接的雙隊列。

首先它的內存佔用雖然散出來的內存,所以你不會有分配一大塊連續內存了蝙蝠的權利。

其次,您將看到更快的入隊和出隊訪問時間,因爲與標準列表中的不同,當您移除可以說中間元素時,不需要在索引中滑動列表的其餘部分,而這需要花費大量列表中的時間。

你會看到O I還應該注意,如果您只使用整數,我建議尋找到一個二元堆(日誌^ 2N)訪問時間相比,主要是O(N)與名單。

2

Python使用Reference Count來管理其資源。

import sys 
class foo: 
    pass 

b = foo() 
a = [b, 1] 

sys.getrefcount(b) # gives 3 
sys.getrefcount(a) # gives 2 

a = None # delete the list 
sys.getrefcount(b) # gives 2 

在上面的例子中,B的引用計數會當你把它變成一個列表遞增,因爲你可以看到,當你刪除列表,B的引用計數減得到過。所以在你的代碼

def release_list(a): 
    del a[:] 
    del a 

是多餘的。

總之,所有你需要做的就是分配列表爲無物,或使用關鍵字德爾從屬性字典中刪除列表。 (a.k.a,將名稱與實際對象解除綁定)。例如,

a = None # or 
del a 

當一個對象的引用計數爲零,蟒蛇會免費爲您的記憶。爲了確保對象被刪除,您必須確保沒有其他地方通過名稱或容器引用對象。

sys.getrefcount(b) # gives 2 

如果sys.getrefcount給你2,這意味着你是唯一一個誰的對象的引用,當你做

b = None 

它會被從內存中釋放。