buddy内存分配算法

来源:互联网 发布:mac邮箱怎么设置签名 编辑:程序博客网 时间:2024/05/21 20:08

1 普通内存分配方式的缺点以及解决方法:

1.1 普通的动态内存分配方式(如c语言运行库的内存分配malloc、free):

分配时,是在堆的空闲链表上,查找到第一块空闲的并且足够大的内存,然后对这块内存进行分割,分割一块足够的内存给调用者,剩余部分作为一个新的节点链接到空闲链表里面去;释放时,查找与被释放内存区域连续的节点,如有找到,则合并,如无,则作为一个新的节点放回空闲链表里面去。

1.2 普通的动态内存分配缺点:

多次分配、释放内存操作后,可能会产生大量的外部碎片(下面红色表示已分配的内存块,绿色表示空闲的内存块)。

       例如,经过多次分配后,内存块分布如下所示:

|-------------------------------------------------------------------|------|-------------------------------------------------------------------|------|-------------------------------------------------------------------|

然后有部分内存被释放了,内存块如下所示:

|-------------------------------------------------------------------|------|-------------------------------------------------------------------|------|-------------------------------------------------------------------|

此时,用户申请一块如下所示大小的内存:

|------------------------------------------------------------------------------------------------|

虽然空闲的内存总量比要申请的内存的两倍还多,但由于空闲的内存之间存在着碎片,空闲内存不连续,导致内存无法分配。

1.3 解决方法:

1.3.1 内存地址映射:

应用使用虚拟地址,当内存间存在一定数量的外碎片时,整理内存(将已分配内存拷贝到连续的区域),再将虚拟内存重新进行映射(调整内存映射表);该方法需要芯片支持虚拟内存映射,即芯片带有MMU;

1.3.2 类聚方法:

分配内存时根据大小确定分配内存的位置,使大小相近的部分集中在一起,避免由于大内存被小内存(碎片)分割,该方式对硬件无要求;

2 Buddy 内存分配算法原理及其实现

2.1 Buddy内存分配算法原理:

2.1.1 需求:

a. 如1.3.2;

b.分配小内存时,要尽可能满足数量上的需求;

c.分配大内存时,要尽可能满足大小上的要求;

2.1.2 实现方式:

需求a要求大小相近的放在一起,需求b和c要求不能用固定位置的方式放,即小内存和大内存是共享一块堆内存空间的。

所以,实现应该是分配内存时,搜索空闲的内存链表,在满足要求的所有节点中,找出这样的节点:

a.如果内存块大小与之相差较小,无需分割,直接分配给用户;

b.如找不到a,那么,需要分割,分割后最好做到分割后,再次申请相近大小的内存时,找到a这样的节点;

c.如找不到b,那么,应分割最小的节点,减少在大内存间产生小碎片的可能性;

2.1.3 Buddy算法思想

a. 注意到实现方式点b,它实际上暗示了该实现方式用的就是二分法;

b. 上面一点结合实现方式点c,提出的需求是,如果二分法分完后,还有大块内存存在,应再产生实现点b,亦即是说,对残余的内存逐步二分,直至产生实现方式b;

2.1.4 Buddy算法过程

a. 初始内存状态如下所示:

|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

b.分配内存:

|----------------------|----------------------|-------------------------------------------|------------------------------------------------------------------------------------------------|

c.再分配内存:

|----------------------|-----------|----------|-------------------------------------------|------------------------------------------------------------------------------------------------|

d.再分配内存:

|----------------------|-----------|----------|---------------------|---------------------|------------------------------------------------------------------------------------------------|

e.再分配内存(看到了类聚的效果):

|----------------------|-----------|----------|---------------------|---------------------|------------------------------------------------------------------------------------------------|

f.再分配内存:

|----------------------|-----------|----------|---------------------|---------------------|------------------------------------------------------------------------------------------------|

g.释放两块内存:

|----------------------|-----------|----------|-------------------------------------------|------------------------------------------------------------------------------------------------|

h.申请大内存(可以看到,由于小内存集中在一起,没有分割内存,所以可以利用释放掉的两块内存来拼成大内存使用):

|----------------------|-----------|----------|-------------------------------------------|------------------------------------------------------------------------------------------------|

2.1.5 Buddy算法实现

a.内存池的使用:因为使用的是二分法类聚,应先确定二分法分的类型的个数,假设为BUDDY_LEVEL_COUNT,那么最多分配的内存块个数是2的BUDDY_LEVEL_COUNT - 1次方,假定为BUDDY_PAGE_COUNT;假定最小分配大小为BUDDY_PAGE_SIZE,那么内存池的大小应为BUDDY_PAGE_COUNT X BUDDY_PAGE_SIZE;

b.内存管理数据结构:为了快速找到最小的,满足分配需求的空闲内存块,那么,每种内存类都应有一个空闲内存链表,假设链表节点为Buddy_Memory_Node,那么,存储链表的数组应为Buddy_Memory_Node * arrListFree[BUDDY_LEVEL_COUNT],数组里面存储每个等级的内存链表;Buddy_Memory_Node可以使用空闲内存直接存储;为了快速可合并的节点,节点最好是顺序链接起来;

c.初始化:arrListFree里内存单元最大的类的链表指向内存池,其他的为空;

d操作:如2.1.4所示;



原创粉丝点击