Buddy(伙伴的定义):

这里给出伙伴的概念,满足以下三个条件的称为伙伴:
1)两个块大小相同;
2)两个块地址连续;
3)两个块必须是同一个大块中分离出来的;

Buddy算法的优缺点:

1)尽管伙伴内存算法在内存碎片问题上已经做的相当出色,但是该算法中,一个很小的块往往会阻碍一个大块的合并,一个系统中,对内存块的分配,大小是随机的,一片内存中仅一个小的内存块没有释放,旁边两个大的就不能合并。
 
2)算法中有一定的浪费现象,伙伴算法是按2的幂次方大小进行分配内存块,当然这样做是有原因的,即为了避免把大的内存块拆的太碎,更重要的是使分配和释放过程迅速。但是他也带来了不利的一面,如果所需内存大小不是2的幂次方,就会有部分页面浪费。有时还很严重。比如原来是1024个块,申请了16个块,再申请600个块就申请不到了,因为已经被分割了。

3)另外拆分和合并涉及到 较多的链表和位图操作,开销还是比较大的。

Buddy算法的分配原理:

假如系统需要4(2*2)个页面大小的内存块,该算法就到free_area[2]中查找,如果链表中有空闲块,就直接从中摘下并分配出去。如果没有,算法将顺着数组向上查找free_area[3],如果free_area[3]中有空闲块,则将其从链表中摘下,分成等大小的两部分,前四个页面作为一个块插入free_area[2],后4个页面分配出去,free_area[3]中也没有,就再向上查找,如果free_area[4]中有,就将这16(2*2*2*2)个页面等分成两份,前一半挂如free_area[3]的链表头部,后一半的8个页等分成两等分,前一半挂free_area[2]
的链表中,后一半分配出去。假如free_area[4]也没有,则重复上面的过程,知道到达free_area数组的最后,如果还没有则放弃分配。

 

Buddy算法的释放原理:

内存的释放是分配的逆过程,也可以看作是伙伴的合并过程。当释放一个块时,先在其对应的链表中考查是否有伙伴存在,如果没有伙伴块,就直接把要释放的块挂入链表头;如果有,则从链表中摘下伙伴,合并成一个大块,然后继续考察合并后的块在更大一级链表中是否有伙伴存在,直到不能合并或者已经合并到了最大的块(2*2*2*2*2*2*2*2*2个页面)。

整个过程中,位图扮演了重要的角色,如图2所示,位图的某一位对应两个互为伙伴的块,为1表示其中一块已经分配出去了,为0表示两块都空闲。伙伴中无论是分配还是释放都只是相对的位图进行异或操作。分配内存时对位图的
是为释放过程服务,释放过程根据位图判断伙伴是否存在,如果对相应位的异或操作得1,则没有伙伴可以合并,如果异或操作得0,就进行合并,并且继续按这种方式合并伙伴,直到不能合并为止。

Buddy内存管理的实现:

提到buddy 就会想起linux 下的物理内存的管理 ,这里的memory pool 上实现的 buddy 系统

和linux 上按page 实现的buddy系统有所不同的是,他是按照字节的2的n次方来做block的size

实现的机制中主要的结构如下:

整个buddy 系统的结构 :

struct mem_pool_table

{

#define MEM_POOL_TABLE_INIT_COOKIE (0x62756479)

uint32 initialized_cookie; /* Cookie 指示内存已经被初始化后的魔数,  如果已经初始化设置为0x62756479*/

uint8 *mem_pool_ptr;/* 指向内存池的地址*/

uint32 mem_pool_size; /* 整个pool 的size,下面是整个max block size 的大小*/

uint32 max_block_size; /* 必须是2的n次方,表示池中最大块的大小*/   
boolean assert_on_empty; /* 如果该值被设置成TRUE,内存分配请求没有完成就返回 并输出出错信息*/
 uint32 mem_remaining; /* 当前内存池中剩余内存字节数*/                                              
uint32 max_free_list_index; /* 最大freelist 的下标,*/
struct mem_free_hdr_type     *free_lists[MAX_LEVELS];/* 这个就是伙伴系统的level数组*/

#ifdef FEATURE_MEM_CHECK
uint32 max_block_requested;
  uint32 min_free_mem; /* 放mem_remaining */
#endif /* FEATURE_ONCRPC_MEM_CHECK*/
};

这个结构是包含在free node 或alloc node 中的结构:

其中check 和 fill 都被设置为某个pattern
用来检查该node 的合法性
#define MEM_HDR_CHECK_PATTERN ((uint16)0x3CA4)
#define MEM_HDR_FILL_PATTERN ((uint8)0x5C)

typedef struct  tagBuddyMemBlockHeadType

{

mem_pool_type pool; /*回指向内存池*/

uint16 check;

uint8 state; /* bits 0-3 放该node 属于那1级 bit 7 如果置1,表示已经分配(not free)

uint8 fill;

} BUDDY_MEM_BLOCK_HEAD_TYPE;

这个结构就是包含node 类型结构的 free header 的结构:

typedef struct  tagBuddyMemHeadType

{

mem_node_hdr_type hdr;

struct mem_free_hdr_type * pNext;   /* next,prev,用于连接free header的双向 list*/

struct mem_free_hdr_type * pPrev;

} mem_free_hdr_type;

这个结构就是包含node 类型结构的 alloc header 的结构: 
已分配的mem 的node 在内存中就是这样表示的

  1. typedef struct mem_alloc_hdr_type
  2. {
  3. mem_node_hdr_type hdr;
  4. #ifdef FEATURE_MEM_CHECK_OVERWRITE
  5. uint32     in_use_size;
  6. #endif
  7. } mem_alloc_hdr_type;

其中用in_use_size 来表示如果请求分配的size 所属的level上实际用了多少 
比如申请size=2000bytes, 按size to level 应该是2048,实际in_use_size 
为2000,剩下48byte 全部填充为某一数值,然后在以后free 是可以check  
是否有overwite 到着48byte 中的数值,一般为了速度,只 检查8到16byte 

另外为什么不把这剩下的48byte 放到freelist 中其他level 中呢,这个可能 
因为本来buddy 系统的缺点就是容易产生碎片,这样的话就更碎了

关于free or alloc node 的示意图:

假设

最小块为2^4=16,着是由mem_alloc_hdr_type (12byte)决定的, 实际可分配4byte

如果假定最大max_block_size =1024,

如果pool 有mem_free_hdr_type[0]上挂了两个1024的block node

上图是free node, 下图紫色为alloc node

接下来主要是buddy 系统的操作主要包括pool init , mem alloc ,mem free 

pool init : 
 1. 将实际pool 的大小去掉mem_pool_table 结构大小后的size 放到 
     mem_pool_size, 并且修改实际mem_pool_ptr指向前进mem_pool_table 
     结构大小的地址 
 2.  接下来主要将mem_pool_size 大小的内存,按最大块挂到free_lists 上 
    level 为0的list 上,然后小于该level block size 部分,继续挂大下一 
    级,循环到全部处理完成  (感觉实际用于pool的size ,应该为减去 
    mem_pool_table 的大小,然后和最大块的size 对齐,这样比较好, 
    但没有实际测试过) 
     
     
mem alloc: 
    这部分相当简单,先根据请求mem的size ,实际分配时需要加上mem_alloc_hdr_type 
这12byte ,然后根据调整后的size,计算实际应该在那个 level上分配,如果有相应级 
很简单,直接返回,如果没有,一级一级循环查找,找到后,把省下的部分,在往下一级 
一级插入到对应级的freelist 上 

mem free: 
     其中free 的地址,减去12 就可以获得mem_alloc_hdr_type 结构 
     然后确定buddy 在该被free block 前,还是后面, 然后合并buddy, 
     循环寻找上一级的buddy ,有就再合并,只到最大block size 那级 

关于这个算法,在<<The Art  of Computer Programming>> vol 1,的 
动态存储分配中有描述,对于那些只有OSAL 的小系统,该算法相当有用

Buddy内存分配算法的更多相关文章

  1. Java实现内存分配算法 FF(首次适应算法) BF(最佳适应算法)

    一.概述 因为这次os作业对用户在控制台的输入输出有要求,所以我花了挺多的代码来完善控制台的显示. MemoryAlgorithm类里只是和控制台输入输出有关的操作,而对内存的所有逻辑操作都是用Mem ...

  2. python的list内存分配算法

    前提:python为了提高效率会为list预先分配一定的内存空间供其使用,避免在每次append等操作都去申请内存,下面简单分析下list的内存分配算法,主要就是两段. 1.当没有元素时,newsiz ...

  3. Java实现操作系统中四种动态内存分配算法:BF+NF+WF+FF

    1 概述 本文是利用Java实现操作系统中的四种动态内存分配方式 ,分别是: BF NF WF FF 分两部分,第一部分是介绍四种分配方式的概念以及例子,第二部分是代码实现以及讲解. 2 四种分配方式 ...

  4. c模拟内存分配算法(首次适应算法,最佳适应算法,最坏适应算法)

    #include<bits/stdc++.h> using namespace std; /*定义内存的大小为100*/ #define MEMSIZE 100 /*如果小于此值,将不再分 ...

  5. [图解tensorflow源码] [转载] tensorflow设备内存分配算法解析 (BFC算法)

    转载自 http://weibo.com/p/1001603980563068394770   @ICT_吴林阳 tensorflow设备内存管理模块实现了一个best-fit with coales ...

  6. TLFS 内存分配算法详解

    文章目录 1. DSA 背景介绍 1.1 mmheap 1.2 mmblk 2. TLFS 原理 2.1 存储结构 2.2 内存池初始化 2.3 free 2.4 malloc 参考资料 1. DSA ...

  7. MINI3内存分配算法

    最差适应算法 #ifdef USING_WORST_FIT { //先找到第一个满足要求的空洞, //再以第一个为标准寻找最适合的空洞. //当最适合的空洞完全吻合 //就直接划给它,当空洞较大时就切 ...

  8. 内存管理(1)-buddy和slub算法

    Linux内存管理是一个很复杂的系统,也是linux的精髓之一,网络上讲解这方面的文档也很多,我把这段时间学习内存管理方面的知识记录在这里,涉及的代码太多,也没有太多仔细的去看代码,深入解算法,这篇文 ...

  9. 内存分配---FF、BF、WF三种算法

    动态分区分配是根据进程的实际需要,动态的为之分配内存空间.而在实现可变分区分配时,将涉及到分区分配中 所用的数据结构.分区分配算法和分区的分配与内存回收的过程. 分区分配中的数据结构:(1)描述空闲块 ...

随机推荐

  1. [LeetCode] Arranging Coins 排列硬币

    You have a total of n coins that you want to form in a staircase shape, where every k-th row must ha ...

  2. [LeetCode] Self Crossing 自交

    You are given an array x of n positive numbers. You start at point (0,0) and moves x[0] metres to th ...

  3. 自己写的一个Pager分页组件,WebForm,Mvc都适用

    我一说写这个功能的时候,好多人估计有疑问.分页功能网上多的是,搜一个不就行了,你这样不是浪费时间么.你说这句话的时候,我是比较信的,首先自己写一些东西是很耗时,有这些时间又能多打几盘LOL了.但是我觉 ...

  4. 供销大集-JS修改

    aes("a123456") 1.搜索password 可以猜测 寻找匹配项 然后把密码 给t 2.也可以直接直接从这里往上,找到一个 encrypt函数下断点调试输出 funct ...

  5. [转]SQL 常用函数及示例

    原文地址:http://www.cnblogs.com/canyangfeixue/archive/2013/07/21/3203588.html --SQL 基础-->常用函数 --===== ...

  6. Visual Studio 使用Web Deploy 3.6发布项目

    工具:Web Deploy 3.6 点击下载 (强烈推荐使用独立的Web Deploy 安装包安装) 配置: 1.安装web deploy,安装好之后,点击IIS根目录,此处应有如下图标 另外,需要注 ...

  7. MVC其实很简单(Django框架)

    Django框架MVC其实很简单 让我们来研究一个简单的例子,通过该实例,你可以分辨出,通过Web框架来实现的功能与之前的方式有何不同. 下面就是通过使用Django来完成以上功能的例子: 首先,我们 ...

  8. windows中LNK文件打开方式恢复(每日一修(1))

    相信有些用户曾试过错误地把LNK文件的打开方式更改其他文件,导致系统所有的快捷方式都失效.在vista与Windows7系统还不普遍使用的时候,相信大家会有点惊慌失措,不要紧,下面只要大家进行如下操作 ...

  9. 一个简单的CSS3+js 实现3D BOX

    <!doctype html><html><head> <meta charset="UTF-8"> <title>Do ...

  10. NSRunLoop的进一步理解

    iPhone应用开发中关于NSRunLoop的概述是本文要介绍的内容,NSRunLoop是一种更加高明的消息处理模式,他就高明在对消息处理过程进行了更好的抽象和封装,这样才能是的你不用处理一些很琐碎很 ...