
Python內存管理方式和垃圾回收算法解析
在列表,元組,實例,類,字典和函數中存在循環引用問題。有 __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 程序員已然期待的有關局部性內存引用和終結語義的好處。最好是我們能夠找到一個即能使用引用計數,又能夠釋放循環引用的的辦法。
這個方法如何工作?
從概念上講,這個方法與傳統垃圾回收機制相反。這個方法試圖去找到所有的不可訪問對象,而不是去找所有的可訪問對象。這樣更加安全,因為如果這個算法失敗了,起碼不會比不進行垃圾回收還要糟(不考慮我們浪費掉的時間和空間)。
因為我們仍然在用引用計數,垃圾回收器只需要找到循環引用。引用計數會處理其他類型垃圾。首先我們觀察到循環引用只能被容器對象創造。容器對象是可以包含其他對象的引用的對象。在Python中,列表、字典、實例、類和元祖都是容器對象的例子。整數和字符串不是容器。通過這個發現,我們意識到非容器對象可以被垃圾回收忽略。這是一個有用的優化因為整數和字符串這樣的應該比較輕快。
現在我們的想法是記錄所有的容器對象。有幾種方法可以做到,然而最好的一種辦法是利用雙向鏈表,鏈表中的對象結構中包含指針字段。這樣就可以使對象從集合中快速插入刪除,而且不需要額外內存空間分配。當一個容器被創建,它就插入這個集合,被刪除時,就從集合中去除。
既然我們能夠得到所有的容器對象,我們怎么找到循環引用呢?首先我們往容器對象中添加兩個指針外的另一個字段。我們命名這個字段 gc_refs。通過以下幾步我們可以找到循環引用:
對每個容器對象,設 gc_refs 的值為對象的引用計數。
對每個容器對象,找到它引用的其他容器對象并把它們的 gc_refs 值減一。
所有的 gc_refs 大于 1 的容器對象是被容器對象集合外的對象所引用的。我們不能釋放這些對象,所以我們把這些對象放到另一個集合。
被移走的對象所引用的對象也不能被釋放。我們把它們和它們能訪問到的對象都從目前集合移走。
在目前集合中的剩下的對象是僅被該集合中對象引用的(也就是說,他們無法被 Python 取到,也就是垃圾)。我們現在可以去釋放這些對象。
Finalizer的問題
我們的宏偉計劃還有一個問題,就是使用 finalizer 的問題。Finalizer 就是在 Python 中實例的__del__方法。使用引用計數時,Finalizer 工作地不錯。當一個對象的引用計數降到 0 的時候,Finalizer 就在對象被釋放前調用了。對程序員來說這是直接明了且容易理解的。
垃圾回收的時候,調用 finalizer 就成了一個麻煩的問題,尤其是面對循環引用的問題時。如果在循環引用中的兩個對象都有 finalizer,該怎么做?先調用哪個?在調用第一個 finalizer 之后,這個對象無法被釋放因為第二個 finalizer 還能取到它。
因為這個問題沒有好的解決辦法,被有 finalizer 的對象引用的循環是無法釋放的。相反的,這些對象被加進一個全局的無法回收垃圾列表中。程序應該總是可以重新編寫來避免這個問題。作為最后的手段,程序可以讀取這個全局列表并以一種對于當前應用有意義的方式釋放這些引用循環。
代價是什么?
就像有些人說的,天底下沒有免費的午餐。然而,這種垃圾回收形式是相當廉價的。最大的代價之一是每各容器對象額外需要的三個字的內存空間。還有維護容器集合的開銷。對當前版本的垃圾收集器來說,基于 pybench 這個開銷大概是速度下降百分之四。
垃圾回收器目前記錄對象的三代信息。通過調整參數,垃圾回收花費的時間可以想多小就多小。對一些應用來說,關掉自動垃圾回收并在運行時顯式調用也許是有意義的。然而,以默認的垃圾回收參數運行 pybench,垃圾回收花費的時間看起來并不大。顯而易見,大量分配容器對象的應用會引起更多的垃圾回收時間。
目前的補丁增加了一個新的配置項來激活垃圾回收器。有垃圾回收器的 Python 與標準 Python 是二進制兼容的。如果這個選項是關閉的,對 Python 解釋器的工作就沒有影響。
我該怎么使用它?
只要下載目前版本的 Python 就可以了。垃圾回收器已經包括在了 2.0 以后的版本中,并且默認是默認開啟的。如果你在用 Python 1.5.2 版,這里有一個也許能工作的老版本的補丁。如果你用的是 Windows 平臺,你可以下載一個用來替代的 python15.dll。
Boehm-Demers 保守垃圾回收
這個補丁增加了一些修改到 Python 1.5.2,以使用 Boehm-Demers 保守垃圾回收。但是你必須先打上這個補丁。依然是采用了引用計數。垃圾回收器只釋放引用計數沒有釋放的內存(即循環引用)。這樣應該性能最好。你需要:
$ cd Python-1.5.2
$ patch -p1 < ../gc-malloc-cleanup.diff
$ patch -p1 < ../gc-boehm.diff
$ autoconf
$ ./configure --with-gc
這個補丁假設你安裝了 libgc.a,使得 -lgc 鏈接選項可用(/usr/local/lib 也應該可以)。如果你沒有這個庫,在編譯以前下載安裝。
目前,這個補丁只在 Linux 上測試過。在其 他Unix 機器上也許也會工作。在我的 Linux 機器上,GC 版本的 Python 通過了所有的回歸測試。
總結
以上就是本文關于Python內存管理方式和垃圾回收算法解析的全部內容,希望對大家有所幫助。
數據分析咨詢請掃描二維碼
若不方便掃碼,搜微信號:CDAshujufenxi
CDA數據分析師證書考試體系(更新于2025年05月22日)
2025-05-26解碼數據基因:從數字敏感度到邏輯思維 每當看到超市貨架上商品的排列變化,你是否會聯想到背后的銷售數據波動?三年前在零售行 ...
2025-05-23在本文中,我們將探討 AI 為何能夠加速數據分析、如何在每個步驟中實現數據分析自動化以及使用哪些工具。 數據分析中的AI是什么 ...
2025-05-20當數據遇見人生:我的第一個分析項目 記得三年前接手第一個數據分析項目時,我面對Excel里密密麻麻的銷售數據手足無措。那些跳動 ...
2025-05-20在數字化運營的時代,企業每天都在產生海量數據:用戶點擊行為、商品銷售記錄、廣告投放反饋…… 這些數據就像散落的拼圖,而相 ...
2025-05-19在當今數字化營銷時代,小紅書作為國內領先的社交電商平臺,其銷售數據蘊含著巨大的商業價值。通過對小紅書銷售數據的深入分析, ...
2025-05-16Excel作為最常用的數據分析工具,有沒有什么工具可以幫助我們快速地使用excel表格,只要輕松幾步甚至輸入幾項指令就能搞定呢? ...
2025-05-15數據,如同無形的燃料,驅動著現代社會的運轉。從全球互聯網用戶每天產生的2.5億TB數據,到制造業的傳感器、金融交易 ...
2025-05-15大數據是什么_數據分析師培訓 其實,現在的大數據指的并不僅僅是海量數據,更準確而言是對大數據分析的方法。傳統的數 ...
2025-05-14CDA持證人簡介: 萬木,CDA L1持證人,某電商中廠BI工程師 ,5年數據經驗1年BI內訓師,高級數據分析師,擁有豐富的行業經驗。 ...
2025-05-13CDA持證人簡介: 王明月 ,CDA 數據分析師二級持證人,2年數據產品工作經驗,管理學博士在讀。 學習入口:https://edu.cda.cn/g ...
2025-05-12CDA持證人簡介: 楊貞璽 ,CDA一級持證人,鄭州大學情報學碩士研究生,某上市公司數據分析師。 學習入口:https://edu.cda.cn/g ...
2025-05-09CDA持證人簡介 程靖 CDA會員大咖,暢銷書《小白學產品》作者,13年頂級互聯網公司產品經理相關經驗,曾在百度、美團、阿里等 ...
2025-05-07相信很多做數據分析的小伙伴,都接到過一些高階的數據分析需求,實現的過程需要用到一些數據獲取,數據清洗轉換,建模方法等,這 ...
2025-05-06以下的文章內容來源于劉靜老師的專欄,如果您想閱讀專欄《10大業務分析模型突破業務瓶頸》,點擊下方鏈接 https://edu.cda.cn/g ...
2025-04-30CDA持證人簡介: 邱立峰 CDA 數據分析師二級持證人,數字化轉型專家,數據治理專家,高級數據分析師,擁有豐富的行業經驗。 ...
2025-04-29CDA持證人簡介: 程靖 CDA會員大咖,暢銷書《小白學產品》作者,13年頂級互聯網公司產品經理相關經驗,曾在百度,美團,阿里等 ...
2025-04-28CDA持證人簡介: 居瑜 ,CDA一級持證人國企財務經理,13年財務管理運營經驗,在數據分析就業和實踐經驗方面有著豐富的積累和經 ...
2025-04-27數據分析在當今信息時代發揮著重要作用。單因素方差分析(One-Way ANOVA)是一種關鍵的統計方法,用于比較三個或更多獨立樣本組 ...
2025-04-25CDA持證人簡介: 居瑜 ,CDA一級持證人國企財務經理,13年財務管理運營經驗,在數據分析就業和實踐經驗方面有著豐富的積累和經 ...
2025-04-25