2011-11-06 23 views

回答

23

Python的標準引用計數機制不能釋放週期,所以你的例子中的結構會泄漏。

supplemental garbage collection facility,但是,在默認情況下啓用,並且應該能夠釋放該結構,如果沒有它的組件可達從外面再和他們沒有__del__()方法

如果他們這樣做,垃圾收集器will not free them,因爲它不能確定一個安全的命令來運行這些__del__()方法。

+5

應該明確聲明,您稱爲「補充」的GC在默認情況下在Python –

+0

@Eli中啓用,您是對的,因此回答相應更新。 –

+3

萬歲!至少,對GC和ref counter以及不使用「垃圾回收器」作爲「引用計數機制」的同義詞的人們(你和Raymond Hettinger)不要混淆!很久以來,我一直對這樣的事實感到困惑,但我一直在閱讀文本,人們在這些文本中表達了他們的想法,好像GC是殺死沒有被引用的對象的責任。在你的回答中,差異是完美表達和清晰的。謝謝。因此,+1 – eyquem

5

Python的GC被設計成遍歷所有活對象沒有外部引用來定位並消除參考週期。

您可以通過運行gc.collect()然後打印gc.garbagegc.get_objects來驗證發生了什麼。

2

如果你使用weakrefs作爲父指針,那麼GC將正常發生。

18

爲了擴展Frédéric的答案,文檔的the "reference counts" section很好地解釋了補充週期檢測。

因爲我發現講解的東西的好方法,以確認我的理解,這裏有一些例子......有了這兩個類:

class WithDel(object): 
    def __del__(self): 
     print "deleting %s object at %s" % (self.__class__.__name__, id(self)) 


class NoDel(object): 
    pass 

創建一個對象,並從a失去了參考觸發__del__方法,由於裁判計數:

>>> a = WithDel() 
>>> a = None # leaving the WithDel object with no references 
deleting WithDel object at 4299615184 

如果我們兩個對象沒有__del__方法之間的參考迴路,一切還是無泄漏,T他的時間感謝週期檢測。首先,使垃圾收集調試輸出:

>>> import gc 
>>> gc.set_debug(gc.DEBUG_COLLECTABLE | gc.DEBUG_UNCOLLECTABLE | gc.DEBUG_OBJECTS) 

然後使兩個對象之間的參考循環:

>>> a = NoDel(); b = NoDel() 
>>> a.other = b; b.other = a # cyclical reference 
>>> a = None; b = None # Leave only the reference-cycle 
>>> gc.collect() 
gc: collectable <NoDel 0x10046ed50> 
gc: collectable <NoDel 0x10046ed90> 
gc: collectable <dict 0x100376c20> 
gc: collectable <dict 0x100376b00> 
4 
>>> gc.garbage 
[] 

(該dict是從物體內部__dict__屬性)

所有很好,直到即使其中一個對象在循環中也包含一個__del__方法:

>>> a = NoDel(); b = WithDel() 
>>> a.other = b; b.other = a 
>>> a = None; b = None 
>>> gc.collect() 
gc: uncollectable <WithDel 0x10046edd0> 
gc: uncollectable <dict 0x100376b00> 
gc: uncollectable <NoDel 0x10046ed90> 
gc: uncollectable <dict 0x100376c20> 
4 
>>> gc.garbage 
[<__main__.WithDel object at 0x10046edd0>] 

正如保羅所說,循環可以用weakref破:

>>> import weakref 
>>> a = NoDel(); b = WithDel() 
>>> a.other = weakref.ref(b) 
>>> b.other = a # could also be a weakref 

然後當b參考WithDel目標丟失,它將被刪除,儘管週期:

>>> b = None 
deleting WithDel object at 4299656848 
>>> a.other 
<weakref at 0x10045b9f0; dead> 

哦,objgraph會有幫助indicated the problematic __del__ method like this

+0

這對我python2,但是,在python3我無法重現泄漏...有什麼改變? – kralyk

+0

@kralyk我想這個pep是負責任的:https://www.python.org/dev/peps/pep-0442/ – ead