Buddy内存分配算法
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 的大小*/
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 在内存中就是这样表示的
- typedef struct mem_alloc_hdr_type
- {
- mem_node_hdr_type hdr;
- #ifdef FEATURE_MEM_CHECK_OVERWRITE
- uint32 in_use_size;
- #endif
- } 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内存分配算法的更多相关文章
- Java实现内存分配算法 FF(首次适应算法) BF(最佳适应算法)
一.概述 因为这次os作业对用户在控制台的输入输出有要求,所以我花了挺多的代码来完善控制台的显示. MemoryAlgorithm类里只是和控制台输入输出有关的操作,而对内存的所有逻辑操作都是用Mem ...
- python的list内存分配算法
前提:python为了提高效率会为list预先分配一定的内存空间供其使用,避免在每次append等操作都去申请内存,下面简单分析下list的内存分配算法,主要就是两段. 1.当没有元素时,newsiz ...
- Java实现操作系统中四种动态内存分配算法:BF+NF+WF+FF
1 概述 本文是利用Java实现操作系统中的四种动态内存分配方式 ,分别是: BF NF WF FF 分两部分,第一部分是介绍四种分配方式的概念以及例子,第二部分是代码实现以及讲解. 2 四种分配方式 ...
- c模拟内存分配算法(首次适应算法,最佳适应算法,最坏适应算法)
#include<bits/stdc++.h> using namespace std; /*定义内存的大小为100*/ #define MEMSIZE 100 /*如果小于此值,将不再分 ...
- [图解tensorflow源码] [转载] tensorflow设备内存分配算法解析 (BFC算法)
转载自 http://weibo.com/p/1001603980563068394770 @ICT_吴林阳 tensorflow设备内存管理模块实现了一个best-fit with coales ...
- TLFS 内存分配算法详解
文章目录 1. DSA 背景介绍 1.1 mmheap 1.2 mmblk 2. TLFS 原理 2.1 存储结构 2.2 内存池初始化 2.3 free 2.4 malloc 参考资料 1. DSA ...
- MINI3内存分配算法
最差适应算法 #ifdef USING_WORST_FIT { //先找到第一个满足要求的空洞, //再以第一个为标准寻找最适合的空洞. //当最适合的空洞完全吻合 //就直接划给它,当空洞较大时就切 ...
- 内存管理(1)-buddy和slub算法
Linux内存管理是一个很复杂的系统,也是linux的精髓之一,网络上讲解这方面的文档也很多,我把这段时间学习内存管理方面的知识记录在这里,涉及的代码太多,也没有太多仔细的去看代码,深入解算法,这篇文 ...
- 内存分配---FF、BF、WF三种算法
动态分区分配是根据进程的实际需要,动态的为之分配内存空间.而在实现可变分区分配时,将涉及到分区分配中 所用的数据结构.分区分配算法和分区的分配与内存回收的过程. 分区分配中的数据结构:(1)描述空闲块 ...
随机推荐
- WPF仿百度Echarts人口迁移图
GitHub地址:https://github.com/ptddqr/wpf-echarts-map/tree/master 关于大名鼎鼎的百度Echarts我就不多说了 不了解的朋友直接看官方的例子 ...
- 在Arcscene绘制管线三维横断面(AE绘制三维点阵文字)
根据数据信息动态生成三维管线及横断面表格.效果图如下: 在获取信息后,直接构造点阵进行文字绘制即可. 绘制IElement代码: /// <summary> /// 绘制三维文字 /// ...
- 因为多余jar包,所报的错
今天,将项目部署到服务器时,出现了上述的错误.于是就开始找度娘了,找啊找,将项目里面的东西翻来覆去的改,不见效果,还多了些莫名其妙的错,当时就懵逼了.在百度上找到的方法都是说有jar包重复,项目里面的 ...
- 一个解析json串并组装echarts的option的函数解析
缘起: 在组装echart页面的时候,遇到这样一个问题,它是一个需要在循环内层的时候,同时循环外层,在内层循环中就要将外层获取的值存入,导致了一种纠缠状态,费了老劲儿,终于得到如下解决.记录之,绿色为 ...
- 使用Mysql Workbench 画E-R图
MySQL Workbench 是一款专为MySQL设计的ER/数据库建模工具.你可以用MySQL Workbench设计和创建新的数据库图示,建立数据库文档,以及进行复杂的MySQL 迁移.这里介绍 ...
- 小猪cms模块继承
TextAction 继承 UserAction 继承 BaseAction 继承 Action TextAction 路径 PigCms\Lib\Action\User UserAction 路径 ...
- android获取位置location为null的问题
12:38:542016-12-23 很多人经常遇到这种问题,主要是获取到位置的信息为null,第一个主要要有权限 <uses-permission android:name="a ...
- TYVJ1035 棋盘覆盖
时间: 1000ms / 空间: 131072KiB / Java类名: Main 描述 给出一张n*n(n<=100)的国际象棋棋盘,其中被删除了一些点,问可以使用多少1*2的多米诺骨牌进行掩 ...
- C#并发编程
并发编程,一直是小白变成(●—●)的一个坎.平时也用到过不少并发编程操作,在这里进行一下记录. 多线程并不是唯一 并发:同时做多件事情. 多线程:并发的一种形式,采用多线程来执行程序. 并行处理:把正 ...
- ubuntu10.04配置XMAPP中的环境变量
1. 显示环境变量:[root@localhost ~]# echo $PATH/usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/usr/lo ...