2013-08-05 55 views
3

背景

我有一個樹結構。在這個樹狀結構,我保持一個節點的孩子作爲一個雙向鏈表:請問python會自動垃圾收集雙向鏈表嗎?

enter image description here
(來源:Doubly linked list

(我選擇了這個結構,由於廣度優先搜索方法創建這個列表)

問題

現在我關心的是如果垃圾回收器可以自動銷燬這個列表。當然,我只保留對這三個根節點的引用。 Afaik GC的原理是,它收集內存中的數據結構,並不指出任何參考。但是在雙向鏈表中,每個節點都是從它的兄弟節點引用的,並且兄弟節點引用節點。所以總是會引用一個節點,而GC永遠不會收集它。

垃圾回收器會處理雙向鏈表嗎?

如果沒有,最簡單的收集方法是什麼?

相關問題:

Why does Lua use a garbage collector instead of reference counting?
Python: Memory usage and optimization when modifying lists

+1

只要你沒有參考你的程序中的任何節點,它應該GC作爲無法訪問...(afaik這隻適用於cython)我也認爲它只會gc,如果你還沒有實現__del__方法(見其他評論的回答) –

+0

是的,最終。但是,如果你需要對垃圾收集進行細粒度控制,我會推薦使用更低級的語言,或者至少是Python的gc庫。 – vroomfondel

回答

9

每個Python實現有不同的垃圾收集機制。通用答案是「是的,如果它是垃圾,它應該被垃圾收集。」但是你可能想要比這更具體的東西。


在CPython中,垃圾回收使用refcounting和循環收集器。如果一個對象的refcount降到0,它就會被清理乾淨。但在你的情況下,當你的列表的所有外部引用消失時,仍然會有內部引用,所以本身的refcount不能解決你的問題。這就是循環收集器的用途。

假設您的節點沒有__del__方法,並且您沒有(直接或間接)禁用「補充垃圾回收」(默認情況下爲啓用),循環收集器將檢測到您的節點都相互引用,但沒有別的東西指向他們,並清理它。 (這可能需要兩道,因爲它使用了代系統)。

可以使用gc模塊來顯式運行,而不是等待它的循環收集器(gc.collect()),或檢查它在做什麼。例如,如果你這樣做:

gc.collect() 
oldcounts = gc.get_counts() 
del last_reference_to_list 
gc.collect() 
newcounts = gc.get_counts() 
print(oldcounts, newcounts) 

...你應該能夠告訴(不完美的可靠性,但不夠好,學習和測試目的),你的節點都走了。


如果你的節點做什麼__del__方法呢?然後你必須給GC一些幫助。你需要做的是打破任何包含__del__方法的對象的循環。最明顯的方式做到這一點,如果你沒有任何節點共享列表之間,是剛剛走列表和del前進後退指針。 (從技術上說,你只需要del一個或另一個,但你不妨做兩個。)如果您需要在節點上的__del__方法,你可能需要一個在頂級dl_list(或tree_node或不管它是什麼擁有這些),所以這是一個明顯的地方。

當然,如果你不需要__del__方法,有一種更簡單的解決方案:剛剛擺脫它。


最後一個可能性是使用weakref的反向鏈接,但對於正向鏈路經常引用。這樣,就沒有可能的循環。但是你必須小心地添加和刪除節點,以確保你永遠不會暫時離開節點,只有一個弱的參考。


如果您使用Jython或IronPython的,垃圾收集與基礎運行時(JVM或.NET),所以你必須閱讀相應的文檔。

PyPy有它自己的垃圾收集器(實際上,可以選擇不同的選項),您可以閱讀關於here的信息。

如果您使用的是不太常見的實現,應該有類似的文檔可用。