动态存储管理之一【严蔚敏】

用户请求系统分配内存:(两种策略)

1)系统继续从高地址的空闲块中进行分配,不理会已分配的内存区是否已经空闲,直到无法满足分配请求时,系统再去回收用户不再使用的空闲块。

2)用户执行完结束,立马分配过的空闲块释放,用户请求分配时,遍历整个内存区,找合适空闲块分配。

可利用空间表实现内存分配方法:

表中包含所有可分配的空闲块,每一块是链表中一个节点。

1)所有用户请求分配存储量大小相同。

2)分配的存储量分为不同规格。如2,4,8字节建立3,5,9字的链表。

3)分配给用户请求内存块大小不固定,可以随需求改变。

其中当用户请求的内存块大小不固定时,对于寻找空闲块的分配策略也不同:

1》首次拟合法。找到第一个不小于n的空闲块,分配给用户,剩下一部分空闲块继续留在表中。(分配时查找表。)

2》最佳拟合法。找到表中不小于n最接近n的分配给用户。(为了避免遍历整个表,将空闲块大小由小到大排序。空闲块大小差别两极分化,分配回收都需查找链表。)

3》最差拟合法。将表中不小于n并且最大的空闲块的一部分分配给用户。(同2,将空闲块由大到小排序。回收时查找。)

边界标识法:(内存大小不固定的情况)

双向循环链表结构。

回收算法:

当用户释放占用块后,系统会回收进行再分配,使物理地址上的空闲块尽可能大,实现了以下机制;

若释放块左右为占用块,释放块作为节点插入到表中。若左空右占则将释放块与左邻区合并为一新节点,左占右空相同。左右皆空则将左右与释放块合并。

#define TRUE 1
 #define FALSE 0
 #define OK 1
 #define ERROR 0
 #define INFEASIBLE -1
  #define FootLoc(p) p+p->size-1
 typedef int Status; // Status是函数的类型,其值是函数结果状态代码,如OK等
 typedef int Boolean; // Boolean是布尔类型,其值是TRUE或FALSE


typedef struct WORD // 字类型
 {
   union
   {
     WORD *llink; // 头部域,指向前驱结点
     WORD *uplink; // 底部域,指向本结点头部
   };
   int tag; // 块标志,0:空闲,1:占用,头部和尾部均有
   int size; // 头部域,块大小
   WORD *rlink; // 头部域,指向后继结点
 }WORD,head,foot,*Space; // *Space:可利用空间指针类型

Space AllocBoundTag(Space &pav,int n) // 算法8.1(首次拟合法)
 { // 若有不小于n的空闲块,则分配相应的存储块,并返回其首地址;否则返回NULL
   // 若分配后可利用空间表不空,则pav指向表中刚分配过的结点的后继结点
   Space p,f;
   for(p=pav;p&&p->size<n&&p->rlink!=pav;p=p->rlink); // 查找不小于n的空闲块
   if(!p||p->size<n) // 找不到,返回空指针
     return NULL;
   else // p指向找到的空闲块
   {
     f=FootLoc(p); // 指向底部
     pav=p->rlink; // pav指向*p结点的后继结点
     if(p->size-n<=e) // 整块分配,不保留<=e的剩余量
     {
       if(pav==p) // 可利用空间表变为空表
         pav=NULL;
       else // 在表中删除分配的结点
       {
         pav->llink=p->llink;
         p->llink->rlink=pav;
       }
       p->tag=f->tag=1; // 修改分配结点的头部和底部标志
     }
     else // 分配该块的后n个字(高地址部分)       
     { 
       f->tag=1; // 修改分配块的底部标志
       p->size-=n; // 置剩余块大小
       f=FootLoc(p); // 指向剩余块底部
       f->tag=0; // 设置剩余块底部
       f->uplink=p;
       p=f+1; // 指向分配块头部
       p->tag=1; // 设置分配块头部
       p->size=n;
     }
     return p; // 返回分配块首地址
   }
 }

void Reclaim(Space &pav,Space &p)
 { // 边界标识法的回收算法
   Space s=(p-1)->uplink,t=p+p->size; // s、t分别指向释放块的左、右邻块(空闲时)的首地址
   int l=(p-1)->tag,r=(p+p->size)->tag; // l、r分别指示释放块的左、右邻块是否空闲
   if(!pav) // 可利用空间表空
   {    // 将释放块加入到pav所指的可利用空间表中
     pav=p->llink=p->rlink=p; // 头部域的两个指针及pav均指向释放块
        p->tag=0; // 修改头部域块标志为空闲
     (FootLoc(p))->uplink=p; // 修改尾部域
     (FootLoc(p))->tag=0;
   }
   else // 可利用空间表不空
   {  
     if(l==1&&r==1) // 左右邻区均为占用块
     {  
       p->tag=0; // 修改头部域块标志为空闲
       (FootLoc(p))->uplink=p; // 修改尾部域
       (FootLoc(p))->tag=0;
       pav->llink->rlink=p; // 将p所指结点(刚释放的结点)插在pav所指结点之前
       p->llink=pav->llink;
       p->rlink=pav;
       pav->llink=p;
       pav=p; // 修改pav,令刚释放的结点为下次分配时的最先查询的结点
     }
     else if(l==0&&r==1) // 左邻区为空闲块,右邻区为占用块
     {    // 合并左邻块和释放块
       s=(p-1)->uplink; // 左邻空闲块的头部地址
       s->size+=p->size; // 设置新的空闲块大小
       t=FootLoc(p); // 设置新的空闲块底部
       t->uplink=s;
       t->tag=0;
     }
     else if(l==1&&r==0) // 右邻区为空闲块,左邻区为占用块
     { // 合并右邻块和释放块
       p->tag=0; // P为合并后的结点头部地址
       p->llink=t->llink; // p的前驱为原t的前驱
       p->llink->rlink=p; // p的前驱的后继为p
       p->rlink=t->rlink; // p的后继为原t的后继
       p->rlink->llink=p; // p的后继的前驱为p
       p->size+=t->size; // 新的空闲块的大小
       (FootLoc(t))->uplink=p; // 底部(原t的底部)指针指向新结点的头部
       if(pav==t) // 可利用空间表的头指针指向t(t已不是空闲结点首地址了)
         pav=p; // 修改pav,令刚释放的结点为下次分配时的最先查询的结点
     }
     else // 左右邻区均为空闲块
     {
       s->size+=p->size+t->size; // 设置新结点的大小
       t->llink->rlink=t->rlink; // 删去右邻空闲块结点
       t->rlink->llink=t->llink;
       (FootLoc(t))->uplink=s; // 新结点底部(原t的底部)指针指向其头部
       if(pav==t) // 可利用空间表的头指针指向t(t已不是空闲结点首地址了)
         pav=s; // 修改pav,令刚释放的结点为下次分配时的最先查询的结点
     }
   }
   p=NULL; // 令刚释放的结点的指针为空
 }


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值