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] Fraction to Recurring Decimal 分数转循环小数

    Given two integers representing the numerator and denominator of a fraction, return the fraction in ...

  2. 深入理解numpy

    一.为啥需要numpy python虽然说注重优雅简洁,但它终究是需要考虑效率的.别说运行速度不是瓶颈,在科学计算中运行速度就是瓶颈. python的列表,跟java一样,其实只是一维列表.一维列表相 ...

  3. mysql的explain学习

    explain是用来获取sql执行计划的信息. 上面是一个最简单的sql分析.下面来分析每列的意思. ①id  ②select_type ③ table ④type ⑤possible_key ⑥ke ...

  4. jQuery实现二级菜单

    <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...

  5. C#面向对象设计模式纵横谈——4.Builder 生成器模式(创建型模式)

    动机 (Motivation) 在软件系统中,有时候面临着“一个复杂对象”的创建工作,其通常由各个部分的子对象用一定的算法构成:由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是它们组合 ...

  6. WPF学习系列 游戏-选张图片做成9宫格拼图

    今天要学习一个拼图项目. 目标是传入一张图片,然后将它分成9份,去掉一份,鼠标点击进行拼图. 源文件结构很简单 第一步.新建项目 这一步没什么好说的,新建一个项目就跟源文件结构一样了 第二步.页面布局 ...

  7. COGS 2532. [HZOI 2016]树之美 树形dp

    可以发现这道题的数据范围有些奇怪,为毛n辣么大,而k只有10 我们从树形dp的角度来考虑这个问题. 如果我们设f[x][k]表示与x距离为k的点的数量,那么我们可以O(1)回答一个询问 可是这样的话d ...

  8. bash的管道符与重定向

    管道符"|"可以用来将前面的程序的标准输出stdout(=1)重定向到后一个程序的stdin(=0),但是忽略了stderr. 在bash中使用2>&1 可以表示将s ...

  9. Theano Inplace

    Theano Inplace inplace Computation computation that destroy their inputs as a side-effect. Example i ...

  10. ubuntu安装simplejson模块

    在terminal中输入 sudo apt-get install python-simplejson -y import simplejson print simplejson.dumps(lens ...