1. 程式人生 > >夥伴演算法 Buddy

夥伴演算法 Buddy

               

Hi, Buddy ! 

刺蝟@http://blog.csdn.net/littlehedgehog

關於點陣圖

Linux核心夥伴演算法中每個order 的點陣圖都表示所有的空閒塊,比如我家的電腦記憶體256M(現在連上個qq主頁都比較卡),理論上的order為0的bitmap有256M/(4K*2)塊。為什麼要除以二呢? 因為 點陣圖的某位對應於兩個夥伴塊,為1就表示其中一塊忙,為0表示兩塊都閒。每次alloc或者free要操作夥伴系統時我們都要異或運算,這是因為 所謂異或,是指剛開始兩塊都閒為0,後來其中一塊用了異或一下得1,後來另一塊也用了異或一下得0,後來前面一塊回收了異或一下得1,後來另一塊也回收了異或一下得0,這樣(如果為1就不合並)就又可以和前面一塊合併成一大塊了。

點陣圖的主要用途是在回收演算法中指示是否可以和夥伴塊合併,分配時只要搜尋空閒連結串列就足夠了。當然,分配的同時還要對相應位異或一下了,這是為回收演算法服務。

關於分配演算法

假設在初始階段,全是大小為2^9大小的塊( MAX_ORDER為10),序號依次為0, 512, 1024等等,並且所有area的map位都為0(實際上作業系統程式碼要佔一部分空間,但這裡只是舉例),現在要分配一個2^3大小的頁面塊,有以下動作:1. 從order為3的area的空閒連結串列開始搜尋,沒找到就向高一級area搜尋,依次類推,按照假設條件,會一直搜尋到order為9的area,找到了序號為0的2^9頁塊。2. 把序號為0的2^9頁塊從order為9的area的空閒連結串列中摘除並對該area的第0位( 0>>(1+9) )異或一下得1。3. 把序號為0的2^9頁塊拆分成兩個序號分別為0和256的2^8頁塊,前者放入order為8的area的空閒連結串列中,並對該area的第0位( 0>>(1+8) )異或一下得1。4. 把序號為256的2^8頁塊拆分成兩個序號分別為256和384的2^7頁塊,前者放入order為7的area的空閒連結串列中,並對該area的第1位( 256>>(1+7) )異或一下得1。5. 把序號為384的2^7頁塊拆分成兩個序號分別為384和448的2^6頁塊,前者放入order為6的area的空閒連結串列中,並對該area的第3位( 384>>(1+6) )異或一下得1。6. 把序號為448的2^6頁塊拆分成兩個序號分別為448和480的2^5頁塊,前者放入order為5的area的空閒連結串列中,並對該area的第7位( 448>>(1+5) )異或一下得1。7. 把序號為480的2^5頁塊拆分成兩個序號分別為480和496的2^4頁塊,前者放入order為4的area的空閒連結串列中,並對該area的第15位( 480>>(1+4) )異或一下得1。8. 把序號為496的2^4頁塊拆分成兩個序號分別為496和504的2^3頁塊,前者放入order為3的area的空閒連結串列中,並對該area的第31位( 496>>(1+3) )異或一下得1。9. 序號為504的2^3頁塊就是所求的塊。

關於回收演算法

1. 當回收序號為4的1頁塊時,先找到order為0的area,把該頁面塊加入到該area的空閒連結串列中,然後判斷其夥伴塊(序號為5的1頁塊)的狀態,讀該area (不是其它area !)的map的第2位( 4>>(1+order) ),假設夥伴塊被佔,則該位為0(回收4塊前,4、5塊都忙),現異或一下得1,並不再向上合併。2. 當回收序號為5的1頁塊時,同理,先找到order為0的area,把該頁面塊加入到該area的空閒連結串列中,然後判斷其夥伴塊(序號為4的1頁塊)的狀態,讀該area的map的第2位(5>>(1+order) ), 這時該位為1(4塊已回收),現異或一下得0,並向上合併,把序號為4的1頁塊和序號為5的1頁塊從該area的空閒連結串列中摘除,合併成序號為4的2頁塊,並放到order為1的area的空閒連結串列中。同理,此時又要判斷合併後的塊的夥伴塊(序號為6的2頁塊)的狀態,讀該area( order為1的area,不是其它! ) 的map的第1位((4>>(1+order) ),假設夥伴塊在此之前已被回收,則該位為1,現異或一下得0,並向上合併,把序號為4的2頁塊和序號為6的2頁塊從order為1的area的空閒連結串列中摘除,合併成序號為4的4頁塊,並放到order為2的area的空閒連結串列中。然後再判斷其夥伴塊狀態,如此反覆。