成 绩:
***大学计算机学院
课 程 设 计
课 程 操作系统Ⅰ
题 目 存储器管理模拟
学 院 计算机学院
专 业 软件工程
班 级
姓 名
学 号
指导教师 ***
2019 年 6 月 16 日
目 录
1.设计目的与要求
1.1设计目的
1.2设计要求
2.设计思想及系统平台
2.1设计思想
2.2系统平台及使用语言
3.详细算法描述
4.源程序清单
5.运行结果与运行情况
6.总结
1.设计目的与要求
1.1设计目的
本设计的目的是使学生熟悉存储器管理系统的设计方法;加深对所学各种存储器管理方案的了解;要求采用一些常用的存储器分配算法,设计一个存储器管理模拟系统并调试运行。
1.2设计要求
用C++语言分别实现采用首次适应算法和最佳适应算法的动态分区分配过程alloc( )和回收过程free( )。其中,空闲分区通过空闲分区链来管理;首次适应算法在进行内存分配时,系统优先使用空闲区低端的空间。回收时应注意相邻空闲分区的合并。
2.设计思想及系统平台
2.1设计思想
在对数据结构有一定掌握程度的情况下设计合理的数据结构来描述存储空间,实现分区存储管理的内存分配功能,选择适应算法(首次适应算法,最佳适应算法),实现分区存储管理的内存回收算法,在这些存储管理中间必然会有碎片的产生,当碎片产生时,进行碎片的拼接。
2.2系统平台及使用语言
平台:Window10,codeblocks17.12
语言:c++
3.详细算法描述
在写这个内存的动态分区模拟算法时,我是用c++中的可变数组来模拟的。分别用一个可变数组表示空闲分区链,和已分配的内存分区链,在收到为进程分配内存请求时,在空闲链找看有没有符合条件的。首次适应算法是先分配低地址段的内存,所以在分配时,先对空闲分区链按首地址排序;最佳适应算法是为进程分配能可以满足的最小分区,所以在分配时,先对空闲分区链按分区的大小排序。相邻空闲分区合并,先按首地址排序,对整个空闲链遍历一遍,如果加上分区大小与后下一个地址相同,就合并。具体请看代码实现。
4.源程序清单
#include<bits/stdc++.h>
#include<iostream>
using namespace std;
struct ready_node{//就绪的进程
int id;//进程编号
int flag;//表是进程的状态,1:表示进入内存,0:表示从内存撤出
int size;//进程长度
};
struct free_node{//空闲区域表的结构体,首地址和长度
int id;//保存在该区域的进行号
int start;//首地址
int len;//长度
int state=0;//状态(0-空闲,1-已分配)
};
vector<free_node> free_list;//保存空闲区域表的内容,分别是区域首址和区域长度
vector<free_node> used_list;//保存已占用区域表的内容,分别是区域首址和区域长度
queue<ready_node> wait_list;//等待的进程队列
int flag;//选择的算法(1-首次适应算法 2-最佳适应算法)
//函数定义
int cmp1(free_node a,free_node b);//按开始地址从小到大排序
int cmp2(free_node a,free_node b);//按分区大小从小到大排序
void Show();//显示空闲区域表和已占用表的信息
void solve();//解决方案
void Alloc(ready_node node);//动态分区分配函数
void Free(ready_node node);//回收过程函数
void Oper_FIRO();//操作函数
int main()
{
solve();
return 0;
}
int cmp1(free_node a,free_node b){
return a.start<b.start;//按开始地址从小到大排序
}
int cmp2(free_node a,free_node b){
return a.len<b.len;//按分区大小从小到大排序
}
void Show(){//显示空闲区域表和已占用表的信息
vector<free_node> qlist;
for(int i=0;i<free_list.size();i++){
qlist.push_back(free_list[i]);
}
for(int i=0;i<used_list.size();i++){
qlist.push_back(used_list[i]);
}
sort(qlist.begin(),qlist.end(),cmp1);//操作之前首先按首地址从小到大排序
printf("----------------------------------------------\n");
printf("| 内存分区的情况: |\n");
printf("----------------------------------------------\n");
printf("----------------------------------------------\n");
for(int i=0; i<qlist.size(); i++){
printf("| 分区号 | 首址 | 分区大小 | 状态 | 进程号 |\n");
printf("| %3d | %3d | %3d ",i+1,qlist[i].start,qlist[i].len);
if(qlist[i].state==0) printf("| 空闲 | ---- |\n");
else printf("| 已分配 | %3d |\n",qlist[i].id);
printf("----------------------------------------------\n");
}
}
void solve(){
free_node fnod;
printf("请输入空闲分区初值(Kb):\n");
cin>>fnod.len;
fnod.start=0;//初始化空闲表
free_list.push_back(fnod);
printf("请输入实现算法:\n");
printf(" 1-首次适应算法\n 2-最佳适应算法\n");
cin>>flag;
ready_node node;
printf("请输入进程号,内存大小(Kb),执行的操作(1-申请,0-释放)\n");
while(scanf("%d%d%d",&node.id,&node.size,&node.flag)){
wait_list.push(node);
Oper_FIRO();
//cout<<node.size<<endl;
printf("请输入进程号,内存大小(Kb),执行的操作(1-申请,0-释放)\n");
}
}
void Alloc(ready_node node){//动态分区分配函数
if(flag==1)//1-首次适应算法
sort(free_list.begin(),free_list.end(),cmp1);
else//2-最佳适应算法
sort(free_list.begin(),free_list.end(),cmp2);
//cout<<free_list.size()<<endl;
free_node fnod;
int ok=0;//表示是否匹配成功
vector<free_node>::iterator it;//定义迭代器
for(it=free_list.begin();it!=free_list.end();++it){
//cout<<(*it).start<<endl;
if(((*it).len) >= node.size){
//记录已占用空间
fnod.len=node.size;
fnod.start=(*it).start;
fnod.id=node.id;
fnod.state=1;
used_list.push_back(fnod);//放入已占用区域表
(*it).start+=node.size;
(*it).len-=node.size;//修改空闲区域表的信息
if((*it).len==0){//剩余空闲长度为0,移除这个空闲区域
free_list.erase(it);
}
ok=1;//已找到匹配
break;
}
}
if(ok==0){//证明当前进程没有匹配成功,则放入就绪队列
//ready_list.push(node);
printf(" | 对不起,内存分配失败! |\n");
}
printf("进程%d申请进入内存,内存占用大小为%dkb:\n",node.id,node.size);
Show();
}
void Free(ready_node node){//回收过程函数
//释放内存的过程中,进程正常都会在内存中出现,这里就假设释放的进程全部合法
free_node fnod;
//node.state=0;
vector<free_node>::iterator it;//定义迭代器
for(it=used_list.begin();it!=used_list.end();++it){
if(((*it).id) == node.id){//找到撤销进程
//回收空闲空间,并放入空闲区域白哦,此时不用记录进程号,因为好没有进程占有空间
fnod.start=(*it).start;
fnod.len=node.size;
fnod.state=0;
free_list.push_back(fnod);//放入空闲区域表
(*it).len-=node.size;//修改占用区域表的信息
if((*it).len==0){//撤销内存后,剩余的占有空间为0,移除这个空闲区域
used_list.erase(it);
}
break;
}
}
sort(free_list.begin(),free_list.end(),cmp1);//操作之前首先按首地址从小到大排序)
vector<free_node>::iterator its;//定义迭代器
its=free_list.begin();
its++;
//相邻空闲区合并
for(it=free_list.begin();it!=free_list.end();++it,++its){
if(its!=free_list.end()){//如果与后面的空闲块
int address=it->start+it->len;
if(address==its->start){
(it->len) += its->len;
free_list.erase(its);
its=it;
it--;
}
}
}
printf("进程%d申请撤销,收回内存大小为%dkb:\n",node.id,node.size);
Show();
}
void Oper_FIRO(){//操作函数
ready_node node;
while(!wait_list.empty()){//操作等待数列,有分配和回收两个过程
node=wait_list.front();
wait_list.pop();
if(node.flag==1){//申请进入内存的进程
Alloc(node);
}
else{//要撤出内存的进程
Free(node);
}
}
}
5.运行结果与运行情况
分别用首次适应和最佳适应算法演示下列请求序列的完整截图:
初始内存空间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-最佳适应算法
6.总结
通过本次的课程设计,使我能够正确运用操作系统课程中所学的基本理论和知识,加深了对进程调度基本概念的理解。在设计过程中,阅读了教材和一些资料,不断的发现问题、提出问题、解决问题,加深自己对这些算法的理解,。在编程和调试的过程中,我们要自己设计用于存储的数据结构,和调试bug来模拟这个过程。通过这样的实验和学习,使我们的知识体系变的更加牢固