熱線電話:13121318867

登錄
首頁精彩閱讀python垃圾回收機制
python垃圾回收機制
2018-03-09
收藏

python垃圾回收機制

現在的高級語言如java,c#等,都采用了垃圾收集機制,而不再是c,c++里用戶自己管理維護內存的方式。自己管理內存極其自由,可以任意申請內存,但如同一把雙刃劍,為大量內存泄露,懸空指針等bug埋下隱患。
對于一個字符串、列表、類甚至數值都是對象,且定位簡單易用的語言,自然不會讓用戶去處理如何分配回收內存的問題。
python里也同java一樣采用了垃圾收集機制,不過不一樣的是,python采用的是引用計數機制為主,標記-清除和分代收集兩種機制為輔的策略。
引用計數機制:
python里每一個東西都是對象,它們的核心就是一個結構體:PyObject

        typedef struct_object {
            int ob_refcnt;
            struct_typeobject *ob_type;
        }PyObject;
PyObject是每個對象必有的內容,其中ob_refcnt就是做為引用計數。當一個對象有新的引用時,它的ob_refcnt就會增加,當引用它的對象被刪除,它的ob_refcnt就會減少

 ** #define Py_INCREF(op)   ((op)->ob_refcnt++)          //增加計數**

 **define Py_DECREF(op)                             //減少計數       **

     if (--(op)->ob_refcnt != 0)    \

         ;        \

     else         \

         __Py_Dealloc((PyObject *)(op))

引用計數為0時,該對象生命就結束了。
引用計數機制的優點:
1、簡單
2、實時性:一旦沒有引用,內存就直接釋放了。不用像其他機制等到特定時機。實時性還帶來一個好處:處理回收內存的時間分攤到了平時。
引用計數機制的缺點:
1、維護引用計數消耗資源
2、循環引用

1
list1 = []
2
list2 = []
3
list1.append(list2)
4
list2.append(list1) , list1與list2相互引用,如果不存在其他對象對它們的引用,list1與list2的引用計數也仍然為1,所占用的內存永遠無法被回收,這將是致命的。
對于如今的強大硬件,缺點1尚可接受,但是循環引用導致內存泄露,注定python還將引入新的回收機制。

上面說到python里回收機制是以引用計數為主,標記-清除和分代收集兩種機制為輔。

1、標記-清除機制

標記-清除機制,顧名思義,首先標記對象(垃圾檢測),然后清除垃圾(垃圾回收)。如圖1:

這里寫圖片描述

                        圖1
首先初始所有對象標記為白色,并確定根節點對象(這些對象是不會被刪除),標記它們為黑色(表示對象有效)。將有效對象引用的對象標記為灰色(表示對象可達,
但它們所引用的對象還沒檢查),檢查完灰色對象引用的對象后,將灰色標記為黑色。重復直到不存在灰色節點為止。最后白色結點都是需要清除的對象。
2、回收對象的組織
    這里所采用的高級機制作為引用計數的輔助機制,用于解決產生的循環引用問題。而循環引用只會出現在“內部存在可以對其他對象引用的對象”,比如:list,class等。
為了要將這些回收對象組織起來,需要建立一個鏈表。自然,每個被收集的對象內就需要多提供一些信息,下面代碼是回收對象里必然出現的。
一個對象的實際結構如圖2:
這里寫圖片描述

圖2
通過PyGC_Head的指針將每個回收對象連接起來,形成了一個鏈表,也就是在1里提到的初始化的所有對象。
3、分代技術
    分代技術是一種典型的以空間換時間的技術,這也正是java里的關鍵技術。這種思想簡單點說就是:對象存在時間越長,越可能不是垃圾,應該越少去收集。
這樣的思想,可以減少標記-清除機制所帶來的額外操作。分代就是將回收對象分成數個代,每個代就是一個鏈表(集合),代進行標記-清除的時間與代內對象
存活時間成正比例關系。
從上面代碼可以看出python里一共有三代,每個代的threshold值表示該代最多容納對象的個數。默認情況下,當0代超過700,或1,2代超過10,垃圾回收機制將觸發。
0代觸發將清理所有三代,1代觸發會清理1,2代,2代觸發后只會清理自己。
下面是一個完整的收集流程:鏈表建立,確定根節點,垃圾標記,垃圾回收~
1、鏈表建立
首先,中里在分代技術說過:0代觸發將清理所有三代,1代觸發會清理1,2代,2代觸發后只會清理自己。在清理0代時,會將三個鏈表(代)鏈接起來,清理1代的時,會鏈接1,2兩代。在后面三步,都是針對的這個建立之后的鏈表。
2、確定根節點
圖1為一個例子。list1與list2循環引用,list3與list4循環引用。a是一個外部引用。
這里寫圖片描述

對于這樣一個鏈表,我們如何得出根節點呢。python里是在引用計數的基礎上又提出一個有效引用計數的概念。顧名思義,有效引用計數就是去除循環引用后的計數。

數據分析咨詢請掃描二維碼

若不方便掃碼,搜微信號:CDAshujufenxi

數據分析師資訊
更多

OK
客服在線
立即咨詢
日韩人妻系列无码专区视频,先锋高清无码,无码免费视欧非,国精产品一区一区三区无码
客服在線
立即咨詢