buddy系统算法

1. 伙伴关系


定义:由一个母实体分成的两个各方面属性一致的两个子实体,这两个子实体就处于伙伴关系。在操作系统分配内存的过程中,一个内存块常常被分成两个大小相等的内存块,这两个大小相等的内存块就处于伙伴关系。它满足 3 个条件 :

  • 两个块具有相同大小记为 2^K 
  • 它们的物理地址是连续的
  • 从同一个大块中拆分出来

 

2 . buddy算法的实现原理


        为了便于页面的维护,将多个页面组成内存块,每个内存块都有 2 的方幂个页,方幂的指数被称为阶 order。在操作内存时,经常将这些内存块分成大小相等的两个块,我们称分成的两个内存块为伙伴块。采用一位来表示它们的伙伴关系,当这个位为 1 表示其中一块在使用,当这个位为 0 表示两个页面快都空闲或者都在使用,系统根据该为为 0 或者为 1 来决定是否使用或者分配该页面块。系统每次分配和回收伙伴块时都要对它们的伙伴位跟 1 进行异或运算。所谓异或是指刚开始时,两个伙伴块都空闲,它们的伙伴位为 0,后来其中一块被使用了 异或一下得 1, 后来另一块也使用了异或一下得 0, 后来前面一块回收了异或一下得 1, 后来另一块也回收了异或一下得 0。

 

        我们通过一个简单的例子来说明该算法的工作原理。该例子是以Linux伙伴算法结构为基础,即把所有的空闲页框分组为11个块链表,每个块链表分别包含大小为1, 2, 4,8, 16, 32, 64, 128, 256,512和1024 个连续的页框。

        假设要请求一个256 个页框的块(即1MB)。算法先在256 个页框的链表中检查是否有一个空闲块。如果没有这样的块,算法会查找下一个更大的页块,也就是,在512 个页框的链表中找一个空闲块。如果存在这样的块,内核就把256 的页框分成两等份,一半用作满足请求,另一半插入到256 个页框的链表中。如果在512 个页框的块链表中也没找到空闲块,就继续找更大的块 — 1024个页框的块。如果这样的块存在,内核把1024个页框块的256 个页框用作请求,然后从剩余的768 个页框中拿512个插入到512个页框的链表中,再把最后的256个插入到256个页框的链表中。如果1024个页框的链表还是空的,算法就放弃并发出错信号。

        以上过程的逆过程就是页框块的释放过程,也是该算法名字的由来。内核试图把大小为b的一对空闲伙伴块合并为一个大小为2b的单独块。满足以下条件的两个块称为伙伴:

  • 两个块具有相同的大小,记作b。
  • 它们的物理地址是连续的。
  • 第一块的第一个页框的物理地址是2×b×212的倍数。

该算法是迭代的,如果它成功合并所释放的块,它会试图合并2b 的块,以再次试图形成更大的块。

注意,上面的例子并没用涉及伙伴位图的操作,这是为了简单说明伙伴算法的原理。

 

 

为了实现高效的伙伴算法,需要实现一些基本的操作:

  • 通过页号查找指定order块链表中伙伴页号

        注意:这里提到伙伴页指的是某页所在的块对应的伙伴块中对应序号的页框。举个例子,40号页框对应order为4的伙伴页为40+16=56。这个概念是作者自创的,主要为了说明问题。

        Linux通过该语句实现:buddy_idx = page_idx ^ (1 << order);

        该语句将page_idx与1 << order异或,实际就是对page_idx进行加或者减2^order(两个伙伴块在order块链表中正好差距2^order个页框),而具体是加还是减取决于page_idx做异或运算的位是0还是1。也就是说若该位为0,则该页的伙伴页应该在其后面(这里指页号顺序),所以要加2^order;而若该位为1,则该页的伙伴也应该在其前面,所以要减去2^order。想想是不是这个道理?实际上这里运用了内存对齐的原理,好好品味一下吧!

  •  通过页号查找对应order的伙伴位

         两个伙伴块由一个伙伴位描述,所以每个块链表只需要pages / (1 << (order+1) )个伙伴位(pages为总的页框数)。

         查询伙伴位的操作是buddy_bit_idx = page_idx >> (order+1)。这个语句比较容易理解,其实2^( order+1) 就是order块链表一对伙伴块的大小,自然page_idx除以该值就得到了伙伴位的偏移。

 

  • 伙伴块的合并

        伙伴块的合并实际就是一个页号对齐操作,page_idx &= buddy_idx,该语句实质就是置page_idx的order位为0。上面是Linux系统内部的实现,当看到这个语句是我就想为什么不直接把0~order位都置0呢,page_idx= page_idx & *#*#(呵呵,原来要写出这样的语句还真是比太容易啊,所以知道原因了吧)






关于Linux内核Buddy算法的具体实现这里就不深入探究了,可以参考下面的博客
http://blog.csdn.net/yunsongice/article/details/5225155


你可能感兴趣的:(算法,linux,工作,图形,linux内核)