概要
在列表,元組,實例,類,字典和函數中存在循環引用問題。有 __del__ 方法的實例會以健全的方式被處理。給新類型添加GC支持是很容易的。支持GC的Python與常規的Python是二進制兼容的。
分代式回收能運行工作(目前是三個分代)。由 pybench 實測的結果是大約有百分之四的開銷。實際上所有的擴展模塊都應該依然如故地正常工作(我不得不修改了標準發行版中的 new 和 cPickle 模塊)。一個叫做 gc 的新模塊馬上就可以用來調試回收器和設置調試選項。
回收器應該是跨平臺可移植的。Python 的補丁版本通過了所有的回歸測試并且跑 Grail、Idle 和 Sketch 的時候沒有任何問題。
自 Python 2.0 和之后的版本,可移植的垃圾回收機制已經包括在其中了。垃圾回收默認是開啟的。請高興些吧!
為什么我們需要垃圾回收?
目前版本的 Python 采用引用計數的方式來管理分配的內存。Python 的每個對象都有一個引用計數,這個引用計數表明了有多少對象在指向它。當這個引用計數為 0 時,該對象就釋放了。引用計數對于多數程序都工作地很好。然而,引用計數有一個本質上的缺陷,是由于循環引用引起的。循環引用最簡單的例子就是一個引用自身的對象。比如:
>>> l = []>>> l.append(l)>>> del l
這個創建的列表的引用計數現在是 1。然而,因為它從 Python 內部已經無法訪問,并且可能沒法再被用到了,它應該被當作垃圾。在目前版本的 Python 中,這個列表永遠不會被釋放。
一般情況下循環引用不是一個好的編程實踐,并且幾乎總該被避免。然而,有時候很難避免制造循環引用,要么則是程序員甚至沒有察覺到循環引用的問題。對于長期運行的程序,比如服務器,這個問題特別令人煩惱。人們可不想他們的服務器因為循環引用無法釋放訪問不到的對象而耗盡內存。對于大型程序,很難發現循環引用是怎么創造出來的。
“傳統的”垃圾回收是怎樣的?
傳統的垃圾回收(比如標記-清除法或者停止-拷貝法)通常工作如下:
找到系統的根對象。根對象就像是全局的環境(比如 Python 中的 __main__ 模塊)和堆棧上的對象。
從這些對象搜索所有的可以訪問的對象。這些對象都是“活躍”的。
釋放其他所有對象。
不幸的是這個方法不能用于當前版本的 Python。由于擴展模塊的工作方式,Python 不能完全地確定根對象集合。如果根對象集合沒法被準確地確定,我們就有釋放仍然被引用的對象的風險。即使用其他方式設計擴展模塊,也沒有可移植的方式來找到當前 C 堆棧上的對象。而且,引用計數提供了一些 Python 程序員已然期待的有關局部性內存引用和終結語義的好處。最好是我們能夠找到一個即能使用引用計數,又能夠釋放循環引用的的辦法。
新聞熱點
疑難解答