操作系统与数据结构的关系
本次基于某个操作系统作业—— 动态分区分配方式的模拟:
(1)c语言实现。
(2)假设初始状态可用内存空间为640KB,并有下面请求序列:
作业1申请130KB ,作业2申请60KB,作业3申请100KB ,作业2释放60KB,
作业4申请200KB ,作业3释放100KB,作业1释放130KB ,作业5申请140KB,
作业6申请60KB ,作业7申请50KB ,作业6释放60KB
分别采用首次适应算法和最佳适应算法进行内存块的分配和回收,要求每次分配和回收后显示出空闲内存分区链的情况。
通过阅读课本:记录
动态分区分配:
又称可变分区分配,它根据进程实际需要,动态分配内存空间给它。
数据结构:
1.描述 空闲分区 的情况;
2.描述 已分配分区 的情况;
·
·
- 常用的数据结构有
1.空闲分区表,在系统中设置一张空闲分区表,用于记录每个空闲分区的情况;
——每个空闲分区占一个表目,表目中包括分区号、分区大小和分区地址等数据项
**图1.1**
2.空闲分区链,为了实现对空闲分区的分配和链接,在每个分区的起始部分
设置一些用于控制分区分配的信息,以及用于链接分区所用的前指向针,在
分区尾部则设置一后向指针;
通过前、后向链接指针,把所有的空闲分区链接成一个双向链;
**图1.2**
为检索方便,在分区尾部重复设置状态位和分区大小表目;
当分区被分配出去以后,把状态位由“0”改为“1”,此时,前后指针无意义。
·
分区号 | 分区大小(KB) | 分区地址(K) | 状态 |
---|---|---|---|
1 | 50 | 85 | 空闲 |
2 | 32 | 155 | 空闲 |
3 | 70 | 275 | 空闲 |
4 | 60 | 532 | 空闲 |
5 | … | … | … |
-------------------------------------------图-1.1 空闲分区表-----------------------------------
·
-----------------------------------图-1.2 空闲链结构-----------------------------------
链表采用双链表结构,data定义为空闲分区表类型,空闲分区表结构体定义表内的四个变量。
- 动态分区操作:
- 1)分配内存
系统应利用某种分配算法,从空闲分区链(表)中找到所需大小的分区。设请求的分区大小为u.size,表中每个空闲分区的大小可表示为m.size。
---------------------图-2.1内存分配流程-------------------------------
这里的分配操作:
按某种分配算法检查内存空间,分配,分配出的内存占用当前空闲空间,
于是在链表结点剩余(m.size=m.size - u.size)
于上流程图中(m.size - u.size<=size),
size是事先规定的不在切割的剩余区的大小,说明多余部分太小,不再切割,
该空闲结点被删除
- 2)回收内存
当进程运行完毕释放内存时,系统根据回收区的首址,从空闲区链(表)中找到相应的插入点,此时可能出现以下四种情况之一:
(1) 回收区与插入点的前一个空闲分区F1相邻接,见图2-2(a)。此时应将回收区与插入点的前一分区合并,不必为回收分区分配新表项,而只需修改其前一分区F1的大小。
(内存分区表地址一般是从上到下地址增加,这里 插入点的地址=上一结点首地址+内存大小)
-----------图-2.2(a)------------
一道例题加深理解:
(2) 回收分区与插入点的后一空闲分区F2相邻接,见图2-2(b)。此时也可将两分区合并,形成新的空闲分区,但用回收区的首址作为新空闲区的首址,大小为两者之和。
-----------图-2.2(b)------------
(3) 回收区同时与插入点的前、后两个分区邻接,见图2-2(c)。此时将三个分区合并,使用F1的表项和F1的首址,取消F2的表项,大小为三者之和。
---------------图-2.2(c)------------
(4) 回收区既不与F1邻接,又不与F2邻接。这时应为回收区单独建立一个新表项,填写回收区的首址和大小,并根据其首址插入到空闲链中的适当位置。
图2-3表示出了内存回收时的流程。
·
3. 基于顺序搜索的动态分区分配算法
- 首次适应(first fit,FF)算法
FF算法要求空闲分区链以地址递增的次序链接。
在分配内存时,从链首开始顺序查找,直至找到一个大小能满足要求的空闲分区为止。
然后再按照作业的大小,从该分区中划出一块内存空间,分配给请求者,余下的空闲分区仍留在空闲链中。
若从链首直至链尾都不能找到一个能满足要求的分区,则表明系统中已没有足够大的内存分配给该进程,
内存分配失败,返回。
- 最佳适应(best fit,BF)算法
每次为作业分配内存时,总是把能满足要求、又是最小的空闲分区分配给作业,避免“大材小用”。
为了加速寻找,该算法要求将所有的空闲分区按其容量以从小到大的顺序形成一空闲分区链。
(在上一算法每次查找前,先排序)
===========================================================
题目:假设初始状态可用内存空间为640KB,并有下面请求序列:
作业1申请130KB ,作业2申请60KB,作业3申请100KB ,作业2释放60KB,
作业4申请200KB ,作业3释放100KB,作业1释放130KB ,作业5申请140KB,
作业6申请60KB ,作业7申请50KB ,作业6释放60KB
分别采用首次适应算法和最佳适应算法进行内存块的分配和回收,要求每次分配和回收后显示出空闲内存分区链的情况。
`
空闲分区表结构描述:
typedef struct Free_PartList //空闲分区表结构设计
{
int ID; //分区号
int size; //分区大小
int address;//分区地址
int flag; //状态
}Elemtype;
·
空闲链结构描述
typedef struct Free_Dnode //空闲双向链表
{
Elemtype date;
struct Free_Dnode *prior;
struct Free_Dnode *next;
}Free_DLinkNode,*FPtr;
初始内存分配
初始化一个640KB内存空间。
/*==========================================
函数功能:初始化一个640KB内存空间
函数输入:无
函数输出:链表头指针
============================================*/
Free_DLinkNode *initialize_DLkList(void)
{
Free_DLinkNode *head;
Free_DLinkNode *last;
//申请一个头结点和640KB空间的结点
head=(Free_DLinkNode *)malloc(sizeof(Free_DLinkNode));
last=(Free_DLinkNode *)malloc(sizeof(Free_DLinkNode));
if(head==NULL) exit(1); //存储空间分配失败
//指针域分配
head->next=last;
head->prior=NULL;
last->prior=head;
last->next=NULL;
//数据域初始化
last->date.address=0;
last->date.flag=FREE;
last->date.ID=FREE;
last->date.size=MAX_Space;
}
·
内存分配操作
//实现内存分配
int alloc(int tag)
{
int ID,size1;
printf("请输入作业号:");
scanf("%d",ID);
printf("请输入所需内存大小:");
scanf("%d",size1);
if (ID<=0 || size1<=0)
{
printf("ERROR,请输入正确的ID和请求大小");break;
}
if (tag==1)//采用首次适应算法
{
if(first_fit(ID,size1))
{
printf("分配成功!");
}
else printf("分配成功!");break;
}
else
{
if (best_fit(ID,size1))
{
printf("分配成功!");
}
else printf("分配成功!");break;
}
}
(每个空闲区的大小m.size,请求分区的大小u.size)
当m.size-u.size<=SIZE(SIZE是事先规定的不再切割的剩余分区的大小),便不再切割,将整个分区分配给请求者。
思路,define一个常量SIZE,在分配内存时当surplus在(0,SIZE)范围时,将内存完全分配;而在内存回收时似乎并不需要操作,虽然在分配内存时,定义一个结点temp存放已分配内存,释放时将temp删掉,然而surplus在该该范围时,完全分配;所以temp仅在surplus大于SIZE时起作用,而此时只需修改if语句即可。
这两位博主写的很详细,超爱。
https://blog.youkuaiyun.com/weixin_39282491/article/details/81045441
https://blog.youkuaiyun.com/qq_38898129/article/details/84947687
附上今晚改的代码
#include<stdio.h>
#include <stdlib.h>
#include <malloc.h>
#define MAX_Size 640
#define FREE 0 //空闲状态
#define BUSY 1 //已用状态
#define SIZE 10//最小分区
typedef struct Free_PartList //空闲分区表结构设计
{
int ID; //分区号
int size; //分区大小
int address;//分区地址
int flag; //状态
}Elemtype;
typedef struct Free_Dnode //空闲双向链表
{
Elemtype date;
struct Free_Dnode *prior;
struct Free_Dnode *next;
}Free_DLinkNode, *FPtr;
Free_DLinkNode *head;
Free_DLinkNode *last;
Free_DLinkNode *initialize_DLkList(void);//初始化
int first_fit(int ID,int size);//首次适应算法
int best_fit(int ID,int size); //最佳适应算法
int alloc(int tag); //内存分配
int free(int ID);//主存回收
void show();//查看分配
void Destroy(Free_DLinkNode *p);//销毁节点
void menu();
Free_DLinkNode *initialize_DLkList(void)
{
//申请一个头结点和640KB空间的结点
head=(Free_DLinkNode *)malloc(sizeof(Free_DLinkNode));
last=(Free_DLinkNode *)malloc(sizeof(Free_DLinkNode));
if(head==NULL) exit(1); //存储空间分配失败
//指针域分配
head->next=last;
head->prior=NULL;
last->prior=head;
last->next=NULL;
//数据域初始化
last->date.address=0;
last->date.flag=FREE;
last->date.ID=FREE;
last->date.size=MAX_Size;
}
//实现内存分配
int alloc(int tag)
{
int ID,size1;
printf("请输入作业号:");
scanf("%d", &ID);
printf("\n请输入所需内存大小:");
scanf("%d", &size1);
if (ID<=0 || size1<=0)
{
printf("\nERROR,请输入正确的ID和请求大小");
return 0;
}
if (tag==1)//采用首次适应算法
{
if(first_fit(ID,size1))
{
printf("\n分配成功!");
}
else printf("\n分配失败!");
return 1;
}
else
{
if (best_fit(ID,size1))
{
printf("\n分配成功!");
}
else printf("\n分配失败!");
return 1;
}
}
int first_fit(int ID, int size)//首次适应算法
{
FPtr temp=(FPtr)malloc(sizeof(Free_DLinkNode));
Free_DLinkNode *p=head->next; //从头结点的下一个结点开始查找
temp->date.ID=ID; //temp —进程占用的内存
temp->date.size=size;
temp->date.flag=BUSY;
while(p)
{
if (p->date.flag==FREE && p->date.size>=size && p->date.size<=size+SIZE)//请求大小刚好满足
{
p->date.flag=BUSY;
p->date.ID=ID;
return 1;
break;
}
if (p->date.flag==FREE && p->date.size>size+SIZE)//free空间大于需求情况
{
//将temp链接在p前
temp->next=p;
p->prior->next=temp;
temp->prior=p->prior;
p->prior=temp;
temp->date.address=p->date.address; //temp的始地址修改为p的始地址
p->date.address=temp->date.address+temp->date.size;//修改 p的始地址
p->date.size-=size; //修改p大小
return 1;
break;
}
p=p->next;
}
return 0;
}
int best_fit(int ID,int size)//最佳适应算法
{
int Surplus;//记录可用内存与需求内存的差值
FPtr temp=(FPtr)malloc(sizeof(Free_DLinkNode));
Free_DLinkNode *p=head->next;
temp->date.ID=ID;
temp->date.size=size;
temp->date.flag=BUSY;
Free_DLinkNode *q=NULL;//记录最佳位置
while(p)//遍历链表,找到第一个可用的空闲区间将他给q
{
if (p->date.flag==FREE&&p->date.size>=size)
{
q=p;
Surplus=p->date.size-size;
break;
}
p=p->next;
}
while(p)//继续遍历,找到更加合适的位置
{
if (p->date.flag==FREE&&p->date.size==size)
{
p->date.flag=BUSY;
p->date.ID=ID;
return 1;
break;
}
if (p->date.flag==FREE&&p->date.size>size)
{
if (Surplus> p->date.size-size)
{
Surplus=p->date.size-size;
q=p;
}
}
p=p->next;
}
if (q==NULL)//如果没有找到位置
{
return 0;
}
else//找到了最佳位置
{
if(Surplus<=SIZE&&Surplus>0)
{
q->date.flag=BUSY;
q->date.ID=ID;
return 1;
}
else
{
temp->next=q;
temp->prior=q->prior;
temp->date.address=q->date.address;
q->prior->next=temp;
q->prior=temp;
q->date.size=Surplus;
q->date.address+=size;
return 1;
}
}
}
int free(int ID)//主存回收
{
Free_DLinkNode *p=head->next;
while(p)
{
if (p->date.ID==ID)//找到要回收的ID区域
{
p->date.flag=FREE;
p->date.ID=FREE;
//判断P与前后区域关系
if (p->prior->date.flag==FREE&&p->next->date.flag!=FREE)
{
p->prior->date.size+=p->date.size;
//相当于把p删掉
p->prior->next=p->next;
p->next->prior=p->prior;
}
if (p->prior->date.flag!=FREE&&p->next->date.flag==FREE)
{
p->date.size+=p->next->date.size;
if(p->next->next)
{
p->next->next->prior=p;
p->next = p->next->next;
}
else p->next=p->next->next;
}
if(p->prior->date.flag==FREE&&p->next->date.flag==FREE)
{
p->prior->date.size+=p->date.size+p->next->date.size;
if(p->next->next)
{
p->next->next->prior=p->prior;
p->prior->next=p->next->next;
}
else p->prior->next=p->next->next;
}
if(p->prior->date.flag!=FREE&&p->next->date.flag!=FREE)
{
}
break;
}
p=p->next;
}
printf("回收成功!\n");
return 1;
}
void Destroy(Free_DLinkNode *p)
{
}
void show()
{
printf("\n************************************************\n");
printf("内存分配情况");
printf("\n************************************************\n");
Free_DLinkNode *p=head->next;
while(p)
{
printf("分区号:");
if (p->date.ID==FREE)
printf("FREE\n");
else printf("%d\n",p->date.ID);
printf("起始地址:%d\n",p->date.address);
printf("内存大小:%d\n",p->date.size);
printf("分区状态:");
if (p->date.flag==FREE)
printf("空闲\n");
else
printf("已分配\n");
printf("************************************************\n");
p=p->next;
}
}
void menu()//菜单
{
int tag=0;
int ID;
initialize_DLkList();
printf("分区模拟:");
while(tag!=5)
{
printf("\n\n输入要进行的操作:");
printf("1-首次适应算法,2-最佳适应算法,3-内存回收,4-显示内存状况,5-退出\n");
scanf("%d", &tag);
switch(tag)
{
case 1:
alloc(tag);
break;
case 2:
alloc(tag);
break;
case 3:
printf("亲输入需要回收的ID号:");
scanf("%d\n", &ID);
free(ID);
break;
case 4:
show();
break;
}
}
}
int main()
{
menu();
}