动态内存管理
2016-05-06 22:10
417 查看
动态存储管理:
若可利用的空间表有若干个不小于 用户所需大小为n的空闲块时,有三种分配策略:
1.首次拟合法:从表头指针开始查找可利用的空间表,将找到的第一个大小不小于n的空闲块的一部分分配给用户;
2.最佳拟合法:将可利用空间表中一个不小于n且最接近n的空闲块的一部分分配给用户。
3.最差拟合法:将可利用空间表中不小于n且是链表中最大的空闲块的一部分分配给用户。
区别:<1>最佳拟合法适用于请求分配的内存大小范围较广的系统,因为按最佳拟合法的原则进行分配时,总是找大小最接近请求的空闲块,由于此系统中可能产生一些存储甚小而无法利用的小片内存,同时也保留了那些很大的内存块以备响应后面将发生的内存量特大的请求,从而使整个链表趋向于结点大小差别甚远的状态;而最差拟合法每次都从内存量最大的结点中进行分配,从而使链表中的结点大小趋于均匀,因此它适合用于请求分配的内存下范较窄的系统;而首次拟合法是随机的,因此它介于两者之间,通常适用于系统事先不掌握运行期间可能出现的请求分配和释放的信息情况;
<2>从时间上来比较,首次拟合法在分配时需要查询可利空间表,而回收时仅需插入表头即可;最差拟合法恰恰相反,分配时无需查表,而回收时为将新的“空闲块”插入链表中的适当位置上,无需进行查找;而最佳拟合法无论分配还是回收,均需查找链表,因此最费时间;
总结:不同的情景需采取不同的方法,通常在选择时需考虑下列因素:
<1>用户的逻辑要求;
<2>请求分配量的大小分布;
<3>分配和释放的频率以及效率对系统的重要性;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1、边界标识法:是操作系统中进行动态分区分配的一种存储管理方法;(最差拟合法)
原理:系统将所有的空闲块链接在一个双重循环链表结构的可利用空间表中,每个内存区的头部和底部两个边界上分别设有标识,以标识该区域为占用块或空闲块;
//////////////////////////////////////////////////////////////////////////////////////////////////////
2、伙伴系统:是操作系统中用到的另一种动态存储管理方法,无论是占用块或是空闲块,其大小均为2的k次幂(k为正整数)。
(何为伙伴:在分配时经常需要将一个大的空闲块分裂成两个大小相等的存储区,这两个由同一块分裂出来的小块就称之为”互为伙伴”)
若可利用的空间表有若干个不小于 用户所需大小为n的空闲块时,有三种分配策略:
1.首次拟合法:从表头指针开始查找可利用的空间表,将找到的第一个大小不小于n的空闲块的一部分分配给用户;
2.最佳拟合法:将可利用空间表中一个不小于n且最接近n的空闲块的一部分分配给用户。
3.最差拟合法:将可利用空间表中不小于n且是链表中最大的空闲块的一部分分配给用户。
区别:<1>最佳拟合法适用于请求分配的内存大小范围较广的系统,因为按最佳拟合法的原则进行分配时,总是找大小最接近请求的空闲块,由于此系统中可能产生一些存储甚小而无法利用的小片内存,同时也保留了那些很大的内存块以备响应后面将发生的内存量特大的请求,从而使整个链表趋向于结点大小差别甚远的状态;而最差拟合法每次都从内存量最大的结点中进行分配,从而使链表中的结点大小趋于均匀,因此它适合用于请求分配的内存下范较窄的系统;而首次拟合法是随机的,因此它介于两者之间,通常适用于系统事先不掌握运行期间可能出现的请求分配和释放的信息情况;
<2>从时间上来比较,首次拟合法在分配时需要查询可利空间表,而回收时仅需插入表头即可;最差拟合法恰恰相反,分配时无需查表,而回收时为将新的“空闲块”插入链表中的适当位置上,无需进行查找;而最佳拟合法无论分配还是回收,均需查找链表,因此最费时间;
总结:不同的情景需采取不同的方法,通常在选择时需考虑下列因素:
<1>用户的逻辑要求;
<2>请求分配量的大小分布;
<3>分配和释放的频率以及效率对系统的重要性;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1、边界标识法:是操作系统中进行动态分区分配的一种存储管理方法;(最差拟合法)
原理:系统将所有的空闲块链接在一个双重循环链表结构的可利用空间表中,每个内存区的头部和底部两个边界上分别设有标识,以标识该区域为占用块或空闲块;
# define MAX_SIZE 1000 //模拟内存总大小 # define e 10 //为了防止申请内存残余而限定的条件 typedef struct WORD //用一个结构体来保存结点信息 { union { struct WORD *llink; //指向前驱 struct WORD *uplink; //指向本身 }; int tag; //是否被占用的状态 int size; //申请空间大小 struct WORD *rlink; //指向后继 }WORD, *Space; # define FootLoc(p) (p+p->size -1) //用来计算结点尾部信息 WORD * InitiWord(Space pav) //初始化 { assert(pav != NULL); pav->llink = pav->rlink = pav; pav->tag = 0; pav->size = MAX_SIZE; FootLoc(pav)->uplink = pav; FootLoc(pav)->tag = 0; return pav; } WORD *Mymalloc(Space *ppav, int size) //申请空间 { Space pav = *ppav; Space p = pav; if (pav == NULL) { return NULL; } do //查找满足需求的内存 { if (p->size>=size) { break; } p = p->rlink; }while (p->llink != p); if (p->size<size)//没有找到 { return NULL; } if (p->size-size<e)//找到了,有内存碎片处理 { if (p->rlink == p) //判断是否只有一块内存 { *ppav = NULL; } else { p->rlink = *ppav; p->llink->rlink = p->rlink; p->rlink->llink = p->llink; } p->tag = 1; p->llink = p->rlink = p; FootLoc(p)->tag = 1; } else { p->rlink = *ppav; p->size -= size; FootLoc(p)->uplink = p; FootLoc(p)->tag = 0; Space q = FootLoc(p)+1; q->llink = q->rlink = q; q->tag = 1; q->size = size; FootLoc(q)->uplink = q; FootLoc(q)->tag = 1; p = q; } return p; } /*注:如果每次分配都从同一个结点开始查找的话,势必会造成存储量小的结点密集在头指针pav所指结点附近,这样会增加查询较大空闲块的时间;反之如果每次分配从不同结点开始找,使分配剩余的小块均匀分布在链表中;方法:在每次分配后,令指针pav指向刚进行过分配的结点的后继结点;*/ //回收算法: void Myfree(Space *ppav, Space p) //释放内存 { if (p == NULL) { return; } p->tag = 0; FootLoc(p)->tag = 0; FootLoc(p)->uplink = p; Space pav =*ppav; int ltag = (p-1)->tag;//物理内存的左 int rtag = (FootLoc(p)+1)->tag;//物理内存的右 if (pav ==NULL) { *ppav = p; p->llink = p->rlink = p; } else { if (ltag == 1 && rtag == 1) //左右内存都已占用 { Space lp = pav->llink; lp->rlink = p; p->llink = lp; p->rlink = pav; pav->llink = p; } else if(ltag == 0 && rtag == 1)//左内存未占用 右内存已占用 { Space L = (p-1)->uplink; L->size += p->size; FootLoc(p)->uplink = L; } else if (ltag == 1 && rtag == 0)//右内存未占用 左内存已占用 { Space R = FootLoc(p)+1; p->size += R->size; if (R->llink == R) { *ppav = p; p->llink = p->rlink = p; } else { p->llink = R->llink; R->llink->rlink = p; p->rlink = R->rlink; R->rlink->llink = p; } FootLoc(R)->uplink = p; } else //左右内存都未占用 { Space L = (p-1)->uplink; Space R = FootLoc(p)+1; R->llink->rlink = R->rlink; R->rlink->llink = R->llink; L->size = L->size+p->size+R->size; FootLoc(R)->uplink = L; } } } ////////////////////////////////////测试/////////////////////////////////////////////////////// # include <stdio.h> # include "boundidentiway.h" void ShowUsed(Space p) //显示已分配的内存信息 { if (p == NULL) { return; } printf("Occupy!\n"); printf("%d, tag = %d, size = %d, tail = %d, tail_tag = %d\n", p, p->tag, p->size, FootLoc(p), FootLoc(p)->tag); } void ShowUNsed(Space p)//显示未已分配的内存信息 { if (p == NULL) { return; } printf("NOccupy!\n"); printf("%d, tag = %d, size = %d, tail = %d, tail_tag = %d\n", p, p->tag, p->size, FootLoc(p), FootLoc(p)->tag); } int main() { WORD Arr[MAX_SIZE]; Space pav = InitiWord(Arr); Space p1 = Mymalloc(&pav, 100); Space p2 = Mymalloc(&pav, 200); ShowUsed(p1); ShowUsed(p2); ShowUNsed(pav); Myfree(&pav, p2); ShowUNsed(pav); return 0; }
//////////////////////////////////////////////////////////////////////////////////////////////////////
2、伙伴系统:是操作系统中用到的另一种动态存储管理方法,无论是占用块或是空闲块,其大小均为2的k次幂(k为正整数)。
(何为伙伴:在分配时经常需要将一个大的空闲块分裂成两个大小相等的存储区,这两个由同一块分裂出来的小块就称之为”互为伙伴”)
# define MAX_KVAL 10 typedef struct Part { struct Part *llink; //指向前驱 int tag; //块标志,0空闲,1占用 int kval; //块大小,值为2的k次幂 struct Part *rlink; //指向后继结点 }PNode, *Partner; typedef struct HeadNode { int size; //空闲块的大小 PNode *first; //链表的表头指针 }HNode,HList[MAX_KVAL+1]; //分配算法 static PNode *s; //内存池的起始地址 int Mypow(int b) //计算2的k次幂 { int s = 1; for (int i=0; i<b; i++) { s *= 2; } return s; } void InitiHeadNode(HNode *hlist) //初始化 { assert(hlist != NULL); for (int i=0; i<MAX_KVAL; i++) { hlist[i].first = NULL; hlist[i].size =Mypow(i); } PNode *p = (PNode *)malloc(sizeof(PNode)*Mypow(MAX_KVAL)); p->llink = p->rlink = p; p->tag = 0; p->kval = MAX_KVAL; s = p; hlist[MAX_KVAL].first = p; hlist[MAX_KVAL].size = Mypow(MAX_KVAL); } PNode * Mymalloc(HNode *hlist, int n) //申请内存块 { assert(hlist != NULL); PNode *p; PNode *left; PNode *right; PNode *q; int i; for (i=0; i<=MAX_KVAL; i++) //查找适合大小的内存块 { if (hlist[i].first != NULL && hlist[i].size >= n+1) { break; } } if (i>MAX_KVAL) //没有找到 { return NULL; } else { p = hlist[i].first; left = p->llink; right = p->rlink; if (p == left) { hlist[i].first = NULL; } else { left->rlink = right; right->llink = left; hlist[i].first = right; } int j; for (j=1; hlist[i-j].size>=n+1; j++) //管理剩下的内存块 { q = p+Mypow(i-j); q->llink =q->rlink = q; q->tag = 0; q->kval = i-j; hlist[i-j].first = q; } p->tag = 1; p->kval = i - (--j); } return p; } //回收算法: static PNode * Buddy(PNode *p, int *flag) { PNode *q; if ((p-s) % Mypow(p->kval+1) == 0) { q = p+Mypow(p->kval); *flag = 0; if (q->kval != p->kval) { return NULL; } } else { q = p-Mypow(p->kval); *flag = 1; if (q->kval != p->kval) { return NULL; } } return q; } void Myfree(HNode *hlist, Partner *p) //释放内存块 { assert(p != NULL); PNode *left; PNode *right; int flag; PNode *q = Buddy(*p, &flag); while(q>= s && q < s+hlist[MAX_KVAL].size && q->tag == 0) //合并空闲块 { if (q->rlink == q) { hlist[q->kval].first = NULL; } else { right = q->rlink; q->llink->rlink = q->rlink; q->rlink->llink = q->llink; if (hlist[q->kval].first == q) { hlist[q->kval].first = right; } } if (flag == 0 ) //调整空闲块的新地址 { (*p)->kval ++; } else { q->kval += 1; (*p) = q; } q =Buddy(*p, &flag); } (*p)->tag = 0; if (hlist[(*p)->kval].first != NULL) //插入空闲块 { left = hlist[(*p)->kval].first->llink; right = hlist[(*p)->kval].first; left->rlink = (*p); (*p)->llink = left; (*p)->rlink = right; right->llink = (*p); hlist[(*p)->kval].first = right; } else { (*p)->llink = (*p)->rlink = (*p); hlist[(*p)->kval].first = (*p); } (*p) = NULL; } //////////////////////////////////测试//////////////////////////////////////////////////////// # include <stdio.h> # include <math.h> # include "partner.h" void AvailSpace(HNode *hlist) { PNode *p; for (int i=0; i<=MAX_KVAL; i++) { if (hlist[i].first != NULL) { p = hlist[i].first; do { printf("空闲块的大小=%d, 标记为=%d \n",Mypow(p->kval), p->tag); p = p->rlink; }while (p != hlist[i].first); printf("\n"); } } } int main() { HList hlist; InitiHeadNode(hlist); printf("总大小为:\n\n"); AvailSpace(hlist); PNode *p = Mymalloc(hlist, 100); printf("申请了100大小的内存块\n\n"); AvailSpace(hlist); PNode *q = Mymalloc(hlist, 200); printf("申请了200大小的内存块\n\n"); AvailSpace(hlist); PNode *s = Mymalloc(hlist, 240); printf("申请了240大小的内存块\n\n"); AvailSpace(hlist); Myfree(hlist, &p); printf("释放了100大小的内存块\n\n"); AvailSpace(hlist); Myfree(hlist, &s); printf("释放了240大小的内存块\n\n"); AvailSpace(hlist); Myfree(hlist, &q); printf("释放了200大小的内存块\n\n"); AvailSpace(hlist); return 0; }
相关文章推荐
- 源代码管理工具之SVN
- runtime-对成员变量操作应用之归档和返归档
- 3月9日作业 信息系统集成专业技术知识 七道题
- opencv的dnn解析
- python 迭代器与生成器 详解
- HTTPS
- redis cluster 集群架构
- 23.二叉树中和为某一值的路径
- 矢量点乘证明
- bootstrapDialog插件集成datatables插件遇到的异常
- Linux--信号
- [bzoj3065]带插入区间K小值
- navicat 如何设置外键
- 程序员修炼之道----从小工到大家读书笔记(一)
- Android 不一样的原生分享
- 【BZOJ2653】middle,主席树(非权值线段树)维护序列和信息+二分答案
- NGINX引入线程池 性能提升9倍
- 《Swift入门》如何在Windows或者ubuntu下安装XCode6环境来开发Swift?
- 看图说说JVM内存
- 第九周总结