实验3 主存储器空间的分配和回收
一、实验内容
主存储器空间的分配和回收。
二、实验目的
一个好的计算机系统不仅要有一个足够容量的、存取速度高的、稳定可靠的主存储器,而且要能合理地分配和使用这些存储空间。当用户提出申请存储器空间时,存储管理必须根据申请者的要求,按一定的策略分析主存空间的使用情况,找出足够的空闲区域分配给申请者。当作业撤离或主动归还主存资源时,则存储管理要收回作业占用的主存空间或归还部分主存空间。主存的分配和回收的实现与主存储器的管理方式有关的,通过本实验帮助学生理解在可变分区管理方式下应怎样实现主存空间的分配和回收。
三、实验原理
模拟在可变分区管理方式下采用最先适应算法实现主存分配和回收。
(1)可变分区方式是按作业需要的主存空间大小来分割分区的。当要装入一个作业时,根据作业需要的主存量查看是否有足够的空闲空间,若有,则按需要量分割一个分区分配给该作业;若无,则作业不能装入。随着作业的装入、撤离,主存空间被分成许多个分区,有的分区被作业占用,而有的分区是空闲的。例如:
操作系统 | 0 ~ 5k |
---|---|
作业1 | 5k ~ 10k |
作业3 | 10k ~ 14k |
空闲区 | 14k ~ 26k |
作业2 | 26k ~ 26k |
空闲区 | 32k ~ 512k |
为了说明哪些区是空闲的,可以用来装入新作业,必须要有一张空闲区说明表,格式如下:
起址 | 长度 | 状态 | |
---|---|---|---|
第一栏 | 4k | 12k | 未分配 |
第二栏 | 32k | 96k | 未分配 |
… | … | … | … |
其中,起址——指出一个空闲区的主存起始地址。
- 长度——指出从起始地址开始的一个连续空闲的长度。
- 状态——有两种状态,一种是“未分配”状态,指出对应的由起址指出的某个长度的区域是空闲区。
(2)当有一个新作业要求装入主存时,必须查空闲区说明表,从中找出一个足够大的空闲区。
有时找到的空闲区可能大于作业需要量,这时应把原来的空闲区变成两部分:一部分分给作业占用;另一部分又成为一个较小的空闲区。为了尽量减少由于分割造成的空闲区,而尽量保存高地址部分有较大的连续空闲区域,以利于大型作业的装入。为此,在空闲区说明表中,把每个空闲区按其地址顺序登记,即每个后继的空闲区其起始地址总是比前者大。
(3)采用最先适应算法(顺序分配算法)分配主存空间。
按照作业的需要量,查空闲区说明表,顺序查看登记栏,找到第一个能满足要求的空闲区。当空闲区大于需要量时,一部分用来装入作业,另一部分仍为空闲区登记在空闲区说明表中。
由于本实验是模拟主存的分配,所以把主存区分配给作业后并不实际启动装入程序装入作业,而用输出“分配情况”来代替。
(4)当一个作业执行结束撤离时,作业所占的区域应该归还,归还的区域如果与其它空闲区相邻,则应合成一个较大的空闲区,登记在空闲区说明表中。
(5)请按最先适应算法设计主存分配和回收的程序。假设初始时主存中没有作业,现按下面序列进行内存的申请与释放:
作业1申请300K,作业2申请100K,作业1释放300K,作业3申请150K,
作业4申请30K, 作业5申请40K, 作业6申请60K, 作业4释放30K。
请你为它们进行主存分配和回收,把空闲区说明表的初值以及每次分配或回收后的变化显示出来或打印出来。
四、算法流程图
五、源程序及注释
#include<bits/stdc++.h>
using namespace std;
const int MAXS=512;
char c;
int counts,num;//统计块数,申请资源个数
typedef struct Task{
char name;
int start;
int length;
char status;//是否分配的标志
}Task;
Task OS[MAXS];
//初始化
void init(){
counts = 1;
OS[0].name = 'F';//未分配空间命名为F
OS[0].start = 0;//起始位置0
OS[0].length = MAXS;
OS[0].status = 'U';//未分配记U,分配记D
}
//插入数据
void insert(int m, int st, int en){
counts++;//每次申请令分区数量加++
for (int i = counts; i > m ; i--)//插入数据
OS[i] = OS[i - 1];
OS[m].start = st;//记录起始位置
OS[m].length = en;//记录长度
}
//删除
void move(int m){
for (int i = m; i < counts - 1; i++)//数据整体向前移覆盖掉m实现删除
OS[i] = OS[i + 1];
counts--;//分区数量--
}
//合并
void remove(int m, int st, int en){
if((OS[m - 1].status == 'D' || m == 0) && (OS[m + 1].status == 'D' || m == counts)){//m前后都已分配则不合并
OS[m].name = 'F';
OS[m].status = 'U';
}else if(OS[m - 1].status == 'U'){//与前一个合并
OS[m - 1].length = OS[m - 1].length + en;//通过改变前面空间长度实现合并
move(m);//删除已合并的m
}else if(OS[m + 1].status == 'U'){//与后一个合并
OS[m].length = OS[m].length + OS[m + 1].length;
OS[m].name = 'F';//修改m状态
OS[m].status = 'U';
move(m + 1);//删除后一个空间
}
}
//输出当前存储器分配情况
void show(){
cout<<"名称\t标识\t起址\t长度\t状态"<<endl;
for(int i = 0; i < counts; i++){
if(OS[i].status == 'U') cout<<"F\t";
else cout<<OS[i].name<<"\t";
cout<<i<<"\t"<<OS[i].start<<"\t"<<OS[i].length<<"\t"<<OS[i].status<<endl;
}
}
//录入数据
void put(){
cout<<"输入申请或者释放的进程名称及空间大小:"<<endl;
cin>>c;
cin>>num;
}
//申请资源
bool apply(){
int i = 0;
int flag = 0;//标记申请成功与否
while(!flag && i < counts){
if(OS[i].length >= num && OS[i].status == 'U'){
if(OS[i].length == num){//刚好相等
OS[i].name = c;
OS[i].status = 'D';
}
else{//分成两部分,未分配的和分配的
insert(i + 1, OS[i].start + num, OS[i].length - num);//用减法实现插入空闲的分区
OS[i + 1].status = 'U'; //标记为空闲
OS[i + 1].name = 'F';
OS[i].name = c;
OS[i].length = num;
OS[i].status = 'D';//标志分配
}
flag = 1;//成功
}
i++;
}
if(flag){
cout<<"申请成功"<<endl;
return true;
}else{
cout<<"没有足够大空间"<<endl;
return false;
}
}
//释放资源
bool free(){
int i = 0;
int flag = 0;//标记释放成功与否
while (!flag && i < counts){
if (OS[i].name == c){//寻找作业
if (OS[i].length == num) remove(i, OS[i].start, OS[i].length);
else{
if (OS[i].length > num){//不全部释放,将作业拆成已分配和未分配
insert(i + 1, OS[i].start + num, OS[i].length - num);
OS[i+1].name = c;
OS[i+1].status = 'D';
OS[i].length = num;
OS[i].status = 'U';
//检查是否能进行合并
if (OS[i-1].status == 'U') remove(i, OS[i].start, OS[i].length);
}else{
cout<<"正使用的数量小于释放的数量"<<endl;
return 0;
}
}
flag = 1;//成功
}
i++;//没找到作业就++
}
if (flag){
cout<<"释放成功"<<endl;
return true;
}else{
cout<<"未找到匹配的进程名称"<<endl;
return false;
}
}
int main(){
int code;
init();
while (1){
cout<<"——————————————————————————————"<<endl;
cout<<"选择操作:"<<" 1.查看 "<<" 2.申请 "<< " 3.释放 "<<" 0.退出 "<<endl;
cin>>code;
switch(code){
case 1: show();break;
case 2: put();
apply();
show();
break;
case 3: put();
free();
show();
break;
case 0: break;
default: cout << "指令错误重新输入!" << endl;
}
cout<<"——————————————————————————————"<<endl;
}
return 0;
}
六、打印的程序运行时初值和运行结果
七、实验小结
通过本次实验初步实现了对主存储器空间的分配和回收的模拟,采用最先适应算法分配主存空间。但并没有在完成的基础上进行优化,没有考虑开销的问题,此方法只适用于小规模得进程调度。实验中采用了结构体数组存储各个块的使用信息及情况,未使用链表,故操作简单。可以实现申请100k的空间。