伙伴算法(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的空闲链表中。然后再判断其伙伴块状态,如此反复。

 

 

 

你可能感兴趣的:(算法,qq,linux内核)