伙伴算法

 1 .原理

       Linux伙伴算法把所有的空闲页面分为10个块组,每组中块的大小是2的幂次方个页面,例如,第0组中块的大小都为20 1个页面),第1组中块的大小为都为212个页面),第9组中块的大小都为29512个页面)。也就是说,每一组中块的大小是相同的,且这同样大小的块形成一个链表。

   我们通过一个简单的例子来说明该算法的工作原理。

   假设要求分配的块其大小为128个页面(由多个页面组成的块我们就叫做页面块)。该算法先在块大小为128个页面的链表中查找,看是否有这样一个空闲块。如果有,就直接分配;如果没有,该算法会查找下一个更大的块,具体地说,就是在块大小为256个页面的链表中查找一个空闲块。如果存在这样的空闲块,内核就把这256个页面分为两等份,一份分配出去,另一份插入到块大小为128个页面的链表中。如果在块大小为256个页面的链表中也没有找到空闲页块,就继续找更大的块,即512个页面的块。如果存在这样的块,内核就从512个页面的块中分出128个页面满足请求,然后从384个页面中取出256个页面插入到块大小为256个页面的链表中。然后把剩余的128个页面插入到块大小为128个页面的链表中。如果512个页面的链表中还没有空闲块,该算法就放弃分配,并发出出错信号。

       以上过程的逆过程就是块的释放过程,这也是该算法名字的来由。满足以下条件的两个块称为伙伴:

·      两个块的大小相同

·      两个块的物理地址连续

伙伴算法把满足以上条件的两个块合并为一个块,该算法是迭代算法,如果合并后的块还可以跟相邻的块进行合并,那么该算法就继续合并。

2.数据结构

6.2.5节中所介绍的管理区数据结构struct zone_struct中,涉及到空闲区数据结构:

free_area_t free_area[MAX_ORDER];

我们再次对free_area_t给予较详细的描述。

#difine   MAX_ORDER  10

    type struct free_area_struct {

           struct list_head   free_list

                 unsigned  int    *map

     } free_area_t


其中list_head域是一个通用的双向链表结构,链表中元素的类型将为mem_map_t(struct page结构)Map域指向一个位图,其大小取决于现有的页面数。free_areak项位图的每一位,描述的就是大小为2k页面的两个伙伴块的状态。如果位图的某位为0,表示一对兄弟块中或者两个都空闲,或者两个都被分配,如果为1,肯定有一块已被分配。当兄弟块都空闲时,内核把它们当作一个大小为2k+1的单独快来处理。如图6.9给出该数据结构的示意图:

                             

                 6.9 伙伴系统使用的数据结构

 6.9中,free_aea数组的元素0包含了一个空闲页(页面编号为0);而元素2则包含了两个以4个页面为大小的空闲页面块,第一个页面块的起始编号为4,而第二个页面块的起始编号为56

我们曾提到,当需要分配若干个内存页面时,用于DMA的内存页面必须是连续的。其实为了便于管理,从伙伴算法可以看出,只要请求分配的块大小不超过512个页面(2KB),内核就尽量分配连续的页面。

 

 

 

1.什么是伙伴

a.两个块大小相同

b.两个块地址连续

c.同属于一个大块,第0块和第1块是伙伴,第2块和第3块是伙伴,但是第1块和第2块不是伙伴)

2。伙伴位图:

伙伴算法通过位图进行操作,用一位描述相邻的两块(第0块和第1块是伙伴,第2块和第3块是伙伴,但是第1块和第2块不是伙伴)的状态。这个位码叫伙伴位码。

为0的时候:说明这两块都为空闲

为1的时候:说明这两块有一块是忙(两块都忙是属于1状态吗?)

注意:这里的块就是本级的单位块。假设现在所属的组是64页,那它的伙伴块就是64页。即两个连续的64页——128页需要一个bit

bitmap_size=内存页区页数/内存页区页数(2^order)/8/2

011001110000

3。基于伙伴算法的内存分配

伙伴算法每次只能分配2的幂次页的空间。

linux以4k页作为页管理的基本单位,一个page结构对应一个页。因为伙伴算法是根据每个zone来的,因此在struct zone的结构体中有一个struct free_area         free_area[MAX_ORDER]成员;MAX_ORDER默认是11,也就是每个zone中有11个free_area结构体,分别是2^0,2^1,……2^10,这就是我们的内存块链表。也就是我们最大分配的内存卡是从free_area[10]中能够获得,大小是2^10页,即4M。(启动之后能获得的最大连续物理空间是4M,要超过4M的连续空间,要么是该order的值,要么是在启动之前就获得,就是在mem_init之前)

struct free_area {

struct list_head        free_list;

unsigned long                nr_free;

};可以看出free_area结构体仅仅包含了一个双向链表,指向了空闲块的前后页,还有一个里面的free的页数。

举个例子:在分配4(2^2)页的时候,系统会先从free_area[2]中查看其成员nr_free是否空,如果空则从中分配,如果free_area[2]中没有空的,就从它的上一级free_area[3]中分配,并将多余的内存块加入到free_area[2]中。如果free_area[3]的nr_free也没有空闲,则从更上一级,以此类推直至free_area[max_order],如果顶级都没有空间,就报告分配失败。

4。基于伙伴算法的内存释放

内存的释放是分配的逆过程,也可以看做是伙伴的合并。当释放一个块时,先在其对应的free_area链表中查找是否有伙伴存在,如果没有伙伴块,直接将要释放的块插入链表头;如果有,则将其从链表下摘下,合并成一个大块,然后继续查找在合并后的块在更大一级链表中是否有伙伴存在,直至不能合并或者已经合并至最大的块2^10为止。

5。伙伴算法的不足:

a。合并的要求太过严格:只能是满足伙伴关系的块。比如第1,2块就不能合并。

b。碎片问题:如何内存管理的算法都存在这个问题,一个连续的内存中仅仅一个页面被占用,导致这整个内存区都不具备合并的条件。

c。算法中的浪费现象:伙伴算法是按2的幂次方分配内存区的,当需要257(2^8+1)个页面时,不得不申请2^9的页面。于是就有255个页面被浪费掉了。

d。算法的效率问题:伙伴算法涉及了比较多的计算还有链表和位图的操作,开销还是比较大的,如果每次2^n大小的伙伴块就会合并到2^(n+1)的链表队列中,那么2^n大小链表中的块就会因为合并操作而减少,但系统随后立即有可能又有对该大小块的需求,为此必须再从2^(n+1)大小的链表中拆分,这样的合并又立即拆分的过程是无效率的。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值