Python垃圾回收機制
Python的垃圾回收機制是主要依靠GC(garbage collector)模塊的引用計數來實現的。但是GC模塊也有它的不足,下來我們來分別介紹下Python的幾種垃圾回收機制。
GC模塊之引用計數
原理
Python中變量的本質是對內存中某一塊內存的引用。Python為每一個引用都維護了一個引用計數的屬性。當一個引用被創建或者被復制時,就給相關對象的引用計數+1;相反當一個引用被銷毀時就把相關對象的引用計數-1。當引用計數為0時,Python就會釋放這個對象多占據的內存空間。
引用計數在每次引用的創建或者銷毀時,都要做一次引用計數改變的操作,當引用創建或者銷毀頻繁時,就會導致效率降低。但是這樣做帶來的好處就是實時性。能夠動態的、及時的管理內存。
其中還存在一個問題,當兩個對象相互引用時,包含自己本身時,就會造成一個循環引用,導致不分內存永遠無法被回收,導致內存泄漏。為了解決這個問題,就引入了標記-清楚機制和分代回收機制。
標記-清除回收機制
原理
當外界沒用引用這兩個對象時,這兩個對象的引用計數都為1,如果識別出這兩個屬於循環引用的話,就減掉1,這樣就可以看了真是的引用數量。
基於上一種思想,現在又對象A、B,從對象A出發,沿着引用找到對象B,把B對象的引用計數減1;然后從對象B出發,沿着引用找到對象A,把A對象的引用計數減1,這樣就去掉了循環引用的關系。
但是這樣做呢有一個不嚴謹的地方,就是如果對象A對對象B是單向引用的話,在到達對象B之前不知道引用了對象A,這樣先給對象B的引用計數減1的話,就會導致對象B稱為不可達的對象。
為了解決這個問題,Python的做法是將內存一分為二,內存C、D,將內存C用來保存真的引用計數,內存D用來做引用計數的副本,然后在這個副本數據上做實驗。內存D中維護兩張表E、F,表E用來保存不可回收的對象,表F保存可被回收的對象,也就是引用計數為0的對象。然后再從表F中找到那些被表E中對象直接或者間接單向引用的對象,把這些移動到表E中,這樣就可以實現讓不應該被回收的對象不被回收,應該被回收的對象都被回收了。
但是這樣做的缺點就是效率不高。
分代回收機制
分代回收的目的是是為了提升垃圾回收的效率。
原理
將系統中的所有內存塊根據其存活時間划分為不同的集合,每一個集合就成為一個“代”,Python默認定義了三代對象集合,垃圾收集的頻率隨着“代”的存活時間的增大而減小,第一代垃圾收集頻率最高,第三代垃圾收集頻率最低。也就是說,活得越長的對象,就越不可能是垃圾,就應該減少對它的垃圾收集頻率。那么如何來衡量這個存活時間:通常是利用幾次垃圾收集動作來衡量,如果一個對象經過的垃圾收集次數越多,可以得出:該對象存活時間就越長。
通常100次為一代。每一個對象都會先進入第一代的集合,當某個對象經歷的100次垃圾回收以后依然存活,則進入第二代,在經歷100次垃圾回收檢測進入第三代。
參考文章
https://www.cnblogs.com/franknihao/p/7326849.html