本实验通过三种分区分配的方法,分别是固定分区分配、可变分区分配及段页式分区分配,从连续内存分区分配方式到离散分区分配方式。段页式的采用减少了碎片的产生,极大地提高了内存空间的利用率,但是却增加了访存的次数,因此,可以采用快表机制,减少访存的次数,对段页式存储管理进行优化。
1、固定分区分配回收内存空间代码
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define getpch(type) (type*)malloc(sizeof(type))
int SIZE;
struct sif //内存分区使用说明表
{
int id;
int size;
int begin_adress;
char status;//F-已分配,T-未分配
struct sif *next;
}*p,*ready=NULL;
typedef struct sif SIF;
int allocate(int size)//分配内存,返回0代表分配成功
{
p=ready;
while(p!=NULL)
{
if((p->status=='T')&&(p->size>=size))
{
p->status='F';
return 1;
}
p=p->next;
}
return 0;
}
void disp()//打印内存分配情况
{
printf("\n 当前内存分配情况如下:\n");
printf("\n |id |size |begin_adress |status \n");
p=ready;
while(p!=NULL)
{
printf("\n %d| %d| %d| %c\n",p->id,p->size,p->begin_adress,p->status);
p=p->next;
}
}
void Input()
{
int num,i,j,d=0,id=0;
SIF *last=ready;
printf("\n 请输入现有内存的大小: (起始地址从0开始) \n");
scanf("%d",&SIZE);
//初始化内存信息
printf("\n 请输入固定分区不同内存块的个数: ");
scanf("%d",&num);
for(i=0; i<num; i++)
{
int n;
printf("\n 请输入%f KB内存的个数: ",pow(2,4+i));
scanf("%d",&n);
for(j=0; j<n; j++)
{
p=getpch(SIF);
p->id=id++;
p->size=(int)(pow(2,4+i));//size是按照2的指数递增的
p->begin_adress=d;
if((rand()%2)==0)//是否被分配初始化
p->status='T';
else
p->status='F';
p->next=NULL;
d+=p->size;
if(d>=SIZE)
{
printf("\n 已超出系统总内存量,%d号分配失败 \n",p->id);
break;
}
if(ready==NULL)
{
ready=p;
last=ready;
}
else
{
last->next=p;
last=last->next;
}
}
}
disp();//打印内存说明表
}
void allocation()
{
int num1;
int i,s;
//给作业分配内存空间
printf("\n 请输入待分配内存的作业个数:");
scanf("%d",&num1);
for(i=0; i<num1; i++)
{
printf("\n 请输入第%d个作业的大小: ",i);
scanf("%d",&s);
if(allocate(s)==1)
{
printf("\n 已为该作业分配内存空间\n");
printf("\n 存储该作业内存空间的详细信息如下:\n");
printf("\n 内存块号:%d, 内存大小:%d \n",p->id,p->size);
}
else
printf("\n 未能该该作业分配内存 \n");
}
disp();
}
void recover()//作业完成后回收资源
{
int i,k,num;
printf("\n 请输入需要释放的作业个数: ");
scanf("%d",&num);
for(i=0; i<num; i++)
{
printf("\n 请输入存储该作业的内存分区说明表的ID \n");
scanf("%d",&k);
p=ready;
while(p!=NULL)
{
if(p->id==k)
{
p->status='T';
printf("\n 已释放该作业所占用的资源 \n");
break;
}
p=p->next;
}
}
disp();
}
int main()
{
int command;
Input();//初始化内存说明表
printf("\n 请输入命令,给作业分配资源输入1,释放资源输入2,退出请输入任意键:\n");
scanf("%d",&command);
while(1)
{
if(command==1)
allocation();
else if(command==2)
recover();
else
break;
printf("\n 请继续输入命令 \n");
scanf("%d",&command);
}
return 0;
}
2、可变分区分配并回收内存空间(首次适应法)
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define getpch(type) (type*)malloc(sizeof(type))
int SIZE;
int id=0;
struct sif //内存分区使用说明表
{
int id;
int size;
int begin_adress;
char status;//F-已分配,T-未分配
struct sif *next;
}*p,*ready=NULL;
typedef struct sif SIF;
int allocate(int size)//分配内存
{
p=ready;
while(p!=NULL)
{
if((p->status=='T')&&(p->size>=size))
{
p->status='F';
if(((p->size)-size)>0)//若分配后存在碎片
{
if((p->next->status)=='T')//若下一相邻存储块未被分配,将此碎片与相邻存储片合并
{
p->next->begin_adress=p->next->begin_adress-(p->size-size);
p->next->size=p->next->size+(p->size-size);
p->next=p->next->next;
}
else//若下一相邻存储块已被分配,为此碎片新建一存储块
{
SIF *q=getpch(SIF);
q->id=id++;
q->size=(p->size)-size;
q->status='T';
q->begin_adress=p->begin_adress+size;
q->next=p->next;
p->next=q;
p->size=size;
}
}
return 1;
}
p=p->next;
}
return 0;
}
void disp()//显示当前内存分配情况
{
printf("\n 当前内存分配情况如下:\n");
printf("\n |id |size |begin_adress |status \n");
p=ready;
while(p!=NULL)
{
printf("\n %d| %d| %d| %c\n",p->id,p->size,p->begin_adress,p->status);
p=p->next;
}
}
void Input()
{
int d=0;
SIF *last=ready;
printf("\n 请输入现有内存的大小: (起始地址从0开始) \n");
scanf("%d",&SIZE);
//初始化内存信息
while(d!=SIZE)
{
p=getpch(SIF);
p->id=id++;
p->size=rand()%(63-1+1)+1;//使用随机函数分配存储块size
p->begin_adress=d;
if((id%2)==1)
p->status='F';
else
p->status='T';
p->next=NULL;
if(d>(SIZE-(p->size)))
{
p->size=SIZE-d;
}
d+=p->size;
if(ready==NULL)
{
ready=p;
last=ready;
}
else
{
last->next=p;
last=last->next;
}
}
disp();//打印内存说明表
}
void allocation()//采用首次适应算法分配内存
{
int num1;
int i,s;
//给作业分配内存空间
printf("\n 请输入待分配内存的作业个数:");
scanf("%d",&num1);
for(i=0; i<num1; i++)
{
printf("\n 请输入第%d个作业的大小: ",i);
scanf("%d",&s);
if(allocate(s)==1)
{
printf("\n 已为该作业分配内存空间\n");
printf("\n 存储该作业内存空间的详细信息如下:\n");
printf("\n 内存块号:%d, 内存大小:%d \n",p->id,p->size);
}
else
printf("\n 未能该该作业分配内存 \n");
}
disp();
}
void recover()//作业完成后回收资源
{
int i,k,num;
printf("\n 请输入需要释放的作业个数: ");
scanf("%d",&num);
for(i=0; i<num; i++)
{
printf("\n 请输入存储该作业的内存分区说明表的ID \n");
scanf("%d",&k);
p=ready;
SIF *q=getpch(SIF);
while(p!=NULL)
{
if(p->id==k)
{
p->status='T';
if((q->status=='T')&&(p->next->status=='T'))//释放资源上下相邻块均未存储信息,合并三块为一块
{
(q->size)+=p->size+p->next->size;
(q->next)=p->next->next;
}
if((q->status=='T')&&(p->next->status=='F'))//相邻上块未分配,下层已分配,合并上层及当前块
{
(q->size)+=p->size;
(q->next)=p->next;
}
if((q->status=='F')&&(p->next->status=='T'))//相邻下块未分配,上层已分配,合并下层及当前块
{
p->size=(p->size)+(p->next->size);
p->next=p->next->next;
}
printf("\n 已释放该作业所占用的资源 \n");
break;
}
q=p;
p=p->next;
}
}
disp();
}
int main()
{
int command;
Input();//初始化内存说明表
printf("\n 请输入命令,给作业分配资源输入1,释放资源输入2,退出请输入任意键:\n");
scanf("%d ",&command);
while(1)
{
if(command==1)
allocation();
else if(command==2)
recover();
else
break;
printf("\n 请继续输入命令 \n");
scanf("%d",&command);
}
return 0;
}
3、段页式存储管理分配内存空间并实现逻辑地址转换功能
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define getpch(type) (type*)malloc(sizeof(type))
int n;//全局变量,段表长度
typedef struct page//页表
{
int id;
int b_num;
struct black *b;
}pg;
typedef struct paragraph//段表
{
int id;//段号
int size;
struct page *adress;//页内地址
}ph;
ph PH[10];
pg PG[10][10];
void disp()
{
printf("\n 当前段表分配情况如下:\n");
printf("\n |id |pagesize |page_b_adress \n");
int i;
for(i=0; i<(int)(sqrt(n)); i++)
{
printf("\n %d\t%d\t%d \n",PH[i].id,PH[i].size,PH[i].adress);
}
printf("\n 当前页表分配情况如下:\n");
int j;
for(i=0; i<(int)(sqrt(n)); i++)
{
printf("\n 第%d段页内分配情况如下:\n",i);
printf("\n |id | b_num \n");
for(j=0;j<(int)(sqrt(PH[i].size));j++)
printf("\n %d\t%d \n",PG[i][j].id,PG[i][j].b_num);
}
}
void Input()//输入函数
{
int i,d,m;
printf("\n 初始化段表 \n");
printf("\n 请输入段表的起始地址、段表的长度:");
scanf("%d%d",&d,&n);
m=d;
for(i=0; i<(int)(sqrt(n)); i++)
{
PH[i].id=i;
int j=rand()%4;
PH[i].size=(int)(pow(2,j));//页表长度
PH[i].adress=m;
m+=PH[i].size;
int k;
for(k=0; k<j; k++)
{
PG[i][k].id=k;//每个页面2KB
PG[i][k].b_num= rand()%(127-0+1)+1;
}
}
disp();
}
int adress_mapping()//地址映射函数
{
int a,b,c,n1=0,d=0;
printf("\n请依次输入作业的段号、段内页号及业内地址: ");
scanf("%d%d%d",&a,&b,&c);
if(a>n)//判断是否越界
{
printf("\n 您输入的段号已越界 \n");
return -1;
}
//若未越界,则进入页表
int j=sqrt(PH[a].size);
if(b>j)
{
printf("\n 您输入的页号已越界 \n");
return -1;
}
//若未越界,则返回物理地址
return PG[a][b].b_num*256+c;
}
int main()
{
Input();
int command;
printf("\n 计算物理地址请按1,退出请按0 \n");
scanf("%d",&command);
while(command==1)
{
printf("\n %d \n",adress_mapping());
printf("\n 计算物理地址请按1,退出请按0 \n");
scanf("%d",&command);
}
}