python之MRO和垃圾回收機制

1、MOR

一、C3算法簡介

爲了解決原來基於深度優先搜索算法不知足本地優先級,和單調性的問題。
python2.3版本以後不論是新式類仍是經典類,查找繼承順序都採用C3算法

 

二、算法原理

C3算法的本質就是Merge, 不斷地把mro()函數返回的隊列進行Merge,規則以下:
(0)
    首先把要查找的類的全部父類的mro找出來,再把全部父類的mro和全部父類進行歸併算法

(1) 
    若是第一個序列的第一個元素,是後續序列的第一個元素,或者在後續序列中沒有再次出現,則將這個元素合併到最終的方法解析順序序列中,
    並從當前操做的所有序列中刪除。

(2)
    若是不符合,則跳過此元素,查找下一個列表的第一個元素,重複1的判斷規則。

 

三、示例

class A(object): pass
class B(A): pass
class C(A): pass
class D(B): pass
class E(C): pass
class F(D,E): pass

# F的mro順序:
# 第一步 找出F全部的父類的MRO
# D  [DBAO]
# E  [ECAO]
# 第二步 把全部父類的MRO 以及 全部的父類作歸併算法
# [DBAO] [ECAO] [DE]
# F + merge([DBAO] [ECAO] [DE])
# 取第一個序列的第一個元素D,它是後續序列[DE]的第一個元素,那麼D是最終序列的第一個元素
# 把D從所有序列中刪除
# B在後續序列中沒有再次出現,那麼B是最終序列的第二個元素
# FD + merge([BAO] [ECAO] [E])
# A在後續序列中出現了,跳過A,查找下一個列表的第一個元素E,E是後續序列的第一個元素,取E
# FDB + merge([AO] [ECAO] [E])
# FDBE + merge([AO] [CAO])
# FDBEC + merge([AO] [AO])
# FDBECAO
print(F.__mro__)

 

2、垃圾回收機制

一、引用計數機制

python中的垃圾回收機制是:引用計數主、標記清除和分代回收爲輔
python裏每個東西都是對象,它們的核心就是一個結構體:PyObject
Python對象和引用是分離的

PyObject是每一個對象必有的內容,其中ob_refcnt就是作爲引用計數。當一個對象有新的引用時,它的ob_refcnt就會增長,當引用它的對象被刪除,
它的ob_refcnt就會減小。

當引用計數爲0時,該對象生命就結束了,就會被清除了。


查看某個變量的引用計數
from sys import getrefcount
print(getrefcount(變量))


引用計數機制的優勢:
1. 簡單
2. 實時性
    一旦沒有引用,內存就直接釋放了。不用像其餘機制等到特定時機。實時性還帶來一個好處:處理回收內存的時間分攤到了平時。

引用計數機制的缺點:
1. 維護引用計數消耗資源
2. 循環引用的時候,這個對象的引用計數永遠不會爲0,這個對象就會一直存在
    d = [1,2,3]
    f = [4,5,6]
    d.append(f)
    f.append(d)

 

二、標記清除

標記清除(Mark—Sweep)算法是一種基於追蹤回收(tracing GC)技術實現的垃圾回收算法。
它分爲兩個階段:
    第一階段是標記階段,GC會把全部的活動對象打上標記。
    第二階段是把那些沒有標記的非活動對象進行回收。

如何判斷哪些是活動對象哪些是非活動對象:
對象之間經過引用(指針)連在一塊兒,構成一個有向圖,對象構成這個有向圖的節點,而引用關係構成這個有向圖的邊。從根對象(root object)出發,
沿着有向邊遍歷對象,可達的(reachable)對象標記爲活動對象,不可達的對象就是要被清除的非活動對象。根對象就是全局變量、調用棧、寄存器。

示例圖:
在上圖中,咱們把小圈當作全局變量,也就是把它做爲root object,
從小圈出發,對象1可直達,那麼它將被標記,對象二、三、6可間接到達也會被標記,
而4和5不可達,那麼一、二、三、6就是活動對象,4和5是非活動對象會被GC回收。

標記清除算法做爲Python的輔助垃圾收集技術主要處理的是一些容器對象,
好比list、dict、tuple,instance等,由於對於字符串、數值對象是不可能形成循環引用問題。
Python使用一個雙向鏈表將這些容器對象組織起來。

不過,這種簡單粗暴的標記清除算法也有明顯的缺點:清除非活動的對象前它必須順序掃描整個堆內存,哪怕只剩下小部分活動對象也要掃描全部對象。

 

三、分代回收

1. 理論解釋
分代回收是一種以空間換時間的操做方式,Python將內存根據對象的存活時間劃分爲不一樣的集合,每一個集合稱爲一個代,Python將內存分爲了3「代」,分別
爲年輕代(第0代)、中年代(第1代)、老年代(第2代),他們對應的是3個鏈表,它們的垃圾收集頻率與對象的存活時間的增大而減少。新建立的對象都會
分配在年輕代,年輕代鏈表的總數達到上限時,Python垃圾收集機制就會被觸發,把那些能夠被回收的對象回收掉,而那些不會回收的對象就會被移到中年
代去,依此類推,老年代中的對象是存活時間最久的對象,甚至是存活於整個系統的生命週期內。同時,分代回收是創建在標記清除技術基礎之上。分代回收
一樣做爲Python的輔助垃圾收集技術處理那些容器對象。



2. 簡單來講
python內存中存放了三代數據,每一代都是鏈表
    0代 年輕的一代
    域值(700, 10, 10)
    當0代鏈表達到域值上限後,觸發0帶的回收
    0代被觸發回收以後沒有被回收的對象放入1代
    0代被回收10次的時候觸發1代回收
    1代沒有被回收對象放入2代
    1代觸發10次的時候觸發2代回收

 

四、總結

當某個條件達到後,觸發了垃圾回收機制,首先在0代中先作引用計數,把引用爲0的對象清除,而後再作標記清除,把沒用的循環引用對象也清除,
再把沒有清除的對象放到1代,當觸發了10次0代回收機制後,會觸發1代的垃圾回收,而後先作引用計數,再作標記清除,觸發10次1代垃圾回收後,
會觸發2代垃圾回收...
相關文章
相關標籤/搜索