天津理工大学《操作系统》实验二,存储器的分配与回收算法实现,代码详解,保姆式注释讲解

实验内容

1. 本实验是模拟操作系统的主存分配,运用可变分区的存储管理算法设计主存分配和回收程序,并不实际启动装入作业。
2. 采用最先适应法、最佳适应法、最坏适应法分配主存空间。
3. 当一个新作业要求装入主存时,必须查空闲区表,从中找出一个足够大的空闲区。若找到的空闲区大于作业需要量,这是应把它分成二部分,一部分为占用区,加一部分又成为一个空闲区。
4. 当一个作业撤离时,归还的区域如果与其他空闲区相邻,则应合并成一个较大的空闲区,登在空闲区表中。
5. 设计的模拟系统中,进程数不小于5,进程调度方式可以采用实验一中的任何一种。
6. 运行所设计的程序,输出有关数据结构表项的变化和内存的当前状态。

设计思想

  • 根据题意,我们需要建立三个二维数组分别代表,输入作业区,已分配作业区和空闲区,这些数组内部存放了对应的起始地址和内存所占空间,对于已分配区则多加了一个作业名称。
    首先我们要先了解最先适应法、最佳适应法和最坏适应法。

  • 最先适应法:
    将进程往尽量低地址空闲区域放,放不下的话在将地址慢慢升高,每一次存放,都从低地址开始寻找满足的空闲区域,直至最高地址,每次存放都从0开始。

  • 最佳适应法:
    和最先适应算法相似,当进程申请空闲的时候,系统都是从头开始查找。空闲区域是从小到大记录的,每次查找都是从最小的开始,直到查找的满足要求的最小空间区域。

  • 最坏适应法:
    该算法与之前两种算法相反,用最大的空闲区域来存储东西

  • 根据上述算法介绍我们了解到,进行作业分配前,我们先要了解用想进行哪种算法,最先和最佳适应算法比较相似,都是要将空闲区进行从小到大进行排序,最先是取0这个位置的空闲区,最佳是取最小的空闲区,当我们将空闲区排序后,这两个方法取的空闲区是一样的。如果是最坏适应算法是选择最大的空闲区,所以我们把空闲区从大到小排列,还是取第一个空闲区。

源码及注释

#include<iostream>
#include <queue>
using namespace std;
//work[10][0]代表作业名称,work[10][1]代表作业占用内存大小
int work[10][2];
//idle[i][0]空闲起始地址,idle[i][1]连续内存空间
int idle[10][2];
//fee[i][0]已分配作业名,fee[i][1]起始地址,fee[i][2]内存占用空间
int fee[10][3];
//ch1选择分配空间或者是回收空间,ch2选择算法
int num = 0,b=1,d,ch1,ch2;
void init(){//起始地址为1,连续内存空间为100idle[0][0]=1;idle[0][1]=100;//作业名为0,起始地址为0,内存占用空间为0fee[0][0]=0;fee[1][1]=0;fee[1][2]=0;//作业名称为0,作业占用内存大小为0work[0][0]=0;work[0][1]=0;//进入循环,循环10次,分别将所有区域进行初始化操作for (int i = 1; i <= 9; i++){/* code */idle[i][0]=0;idle[i][1]=0;fee[i][0]=0;fee[i][1]=0;fee[i][2]=0;work[i][0]=0;work[i][1]=0;}
}
//设置一个计数器,求空闲单元数
void jishu(){for(int i=0;i < 9;i++){if(idle[i][1] != 0)num++;}
}
//设置一个计数器,求作业的个数
void jishu1(){for(int i = 0;i < 9;i++){if(work[i][1] != 0)b++;}
}
//最先适应算法
//将进程往尽量低地址空闲区域放,放不下的话在将地址慢慢升高,每一次存放,都从低地址开始寻找满足的空闲区域,直至最高地址,每次存放都从0开始。
void zuixian(){num = 0;//调用空闲计数器函数jishu();//对空闲区进行冒泡排序,按照空闲区各个位置的起始地址从小到大进行排序for (int i = 0; i < num; i++){for(int j = i; j < num - i - 1; j++){if(idle[j][0] > idle[j+1][0]){int temp = idle[j][0];idle[j][0] = idle[j+1][0];idle[j+1][0] = temp;temp = idle[j][1];idle[j][1] = idle[j+1][1];idle[j+1][1] = temp;}}}
}
//最佳适应算法
//和最先适应算法相似,当进程申请空闲的时候,系统都是从头开始查找。空闲区域是从小到大记录的,每次查找都是从最小的开始,直到查找的满足要求的最小空间区域。
void zuijia(){//调用空闲计数器函数num = 0;jishu();//对空闲区进行冒泡排序,按照空闲区各个位置的起始地址从小到大进行排序for(int i = 0; i < num; i++){for(int j = i; j < num - i - 1; j++){if(idle[j][1] > idle[j+1][1]){int temp = idle[j][0];idle[j][0] = idle[j+1][0];idle[j+1][0] = temp;temp = idle[j][1];idle[j][1] = idle[j+1][1];idle[j+1][1] = temp;}}}
}
//最坏适应算法
//该算法与之前两种算法相反,用最大的空闲区域来存储东西
void zuihuai(){//调用空闲计数器函数num = 0;jishu();//对空闲区进行冒泡排序,按照空闲区各个位置的起始地址从大到小进行排序for(int i = 0; i < num; i++){for(int j = i; j < num - 1 - i; j++){if(idle[j][1] < idle[j+1][1]){int temp = idle[j][0];idle[j][0] = idle[j+1][0];idle[j+1][0] = temp;temp = idle[j][1];idle[j][1] = idle[j+1][1];idle[j+1][1] = temp;}}}
}//回收进程算法
//传入需要回收的作业名称
void huishou(int name){//调用空闲计数器函数和输入作业计数器函数num = 0;b = 0;jishu();jishu1();//参数c为要删除的作业名对应的已分配区域数组的索引,初始状态为-1int c = -1;//遍历数组查找作业名对应的索引for(int k = 0; k <= b; k++){if(fee[k][0] == name){c = k;break;}}//如果上述循环中未在数组中找到与待查作业相同的作业名,则c还是初始值-1,表示要回收的作业不存在if(c == -1) cout<<"要回收的作业不存在!"<<endl;//以下是找到作业名对应索引值得情况,开始回收作业else{//先用冒泡法对空闲区进行排序(按照起始位置从小到大进行排序)(不包括新回收的)for(int i = 0; i < num; i++){for(int j = i; j < num - i - 1; j++){if(idle[j][0] > idle[j+1][0]){int temp = idle[j][0];idle[j][0] = idle[j+1][0];idle[j+1][0] = temp;temp = idle[j][1];idle[j][1] = idle[j+1][1];idle[j+1][1] = temp;}}}}//用冒泡法对空闲区进行排序(按照起始位置从小到大进行排序)(包括新回收的)for(int q = 0; q < num; q++){//将作业的起始位置与空闲区中的起始地址相对应,将这个位置后面的所有进程全部向后移动一个位置,将该作业插入到空闲数组中(这步操作是包括了新回收的部分)if(fee[c][1] <= idle[q][0]){for(int j = num; j >= q; j--){idle[j+1][0] = idle[j][0];idle[j+1][1] = idle[j][1];idle[j][0] = fee[c][1];idle[j][1] = fee[c][2];b++;//如果插入进来的作业地址后面的进程的起始地址等于该作业起始地址+作业所占用的空间if(idle[j+1][0] == idle[j][0] + idle[j][1]){//将该空闲区所占内存空间变成,该空闲内存空间+后面空闲区域所占的内存空间idle[j][1] = idle[j][1] + idle[j+1][1];int s;//在这一节点之后所有空闲区域后移for(int m = j+1; m <= num; m++){//由于新回收的空闲区的内存空间加上了后面空闲区的内存空间,所以要将后面的所有空闲区域往前移动(简单记法:新增空闲空间的后面的空闲空间往前合并了,所以后续的所有空闲空间都要往前走一个位置)idle[m][0] = idle[m+1][0];idle[m][1] = idle[m+1][1];//记录当前新回收的空闲空间的索引值s = m;}//将该空间全部清0,原本是这里面是有待回收作业的信息的,所以要把他置0回收掉变成空闲空间idle[s][0] = 0;idle[s][1] = 0;//由于回收了一个作业,所以作业的计数器记录的数据要减一b--;}//上面的操作是针对待删除区域和后续空闲区域可以合并的情况//下面的操作是针对待删除区域和前面空闲区可以合并的情况if(idle[j-1][0] == idle[j][0]){idle[j-1][1] = idle[j-1][1] + idle[j][1];int s;for(int n = j; j <= num; j++){idle[n][0] = idle[n+1][0];idle[n][1] = idle[n+1][1];s = n;}idle[s][0] = 0;idle[s][1] = 0;b--;}}break;}}//ch2主要是用来记录用户选择那种适应算法的,不同的算法对应不同的参数数值if(ch2 == 1) zuixian();if(ch2 == 2) zuijia();if(ch2 == 3) zuihuai();//找到待删除作业在已分配区域的具体位置,将其后面的所有已分配区域均往前移动,将待删除区域覆盖,作业区域也是相同的原理for(int p = c; c < b-1; c++){fee[c][0] = fee[c+1][0];fee[c][1] = fee[c+1][1];fee[c][2] = fee[c+2][2];work[c][0] = work[c+1][0];work[c][1] = work[c+1][1];}//回收程序完成cout<<"该程序已被成功回收!"<<endl;}void fp(){//判断空闲区和请求区的大小int tag = 0;num = 0;b = 0;jishu();jishu1();for(int j = 0; j < num; j++){//如果请求作业所占内存 < 空闲区所占内存if(work[b][1] < idle[j][1]){//记录作业名称fee[b][0] = work[b][0];//记录本次已分配作业的起始位置(等于其空闲区域的起始位置)fee[b][1] = idle[j][0];//记录本次已分配作业所占用的内存空间fee[b][2] = work[b][1];//将分配前的空闲区域的起始地址 == 空闲起始位置 + 作业所占内存空间idle[j][0] = idle[j][0] + work[b][1];//将分配前的空闲区所占空间 == 空闲区所占空间 - 作业所占空间idle[j][1] = idle[j][1] - work[b][1];//tag参数改为1,表示可分配tag = 1;break;}//如果请求作业所占内存 = 空闲区所占内存else if(work[b][1] == idle[j][1]){//记录作业名称fee[b][0] = work[b][0];//已分配作业所占内存空间 = 待分配的空闲区域内存空间fee[b][1] = idle[j][0];//记录本次已分配作业所占用的内存空间fee[b][2] = work[b][1];//tag参数改为1,表示可分配tag = 1;//由于新分配了一个作业,即少了一块空闲区域,将已分配的空闲区域的后面所有空闲区域全部向前移动一位,清除已分配的空闲区域for(int i = j; i <= num - 1; i++){idle[i][0] = idle[i+1][0];idle[i][1] = idle[i+1][1];}break;}//如果tag还是0的话,则代表待分配作业内存空间 》 空闲区域的内存空间,无法分配else tag = 0;}if(tag == 0) cout<<"作业过大没有足够的储存空间!"<<endl;}//输出展示给用户的函数
void print(){num = 0;b = 1;jishu();jishu1();cout<<"已分配表为:"<<endl;//遍历已分配区域的数组for(int i = 0; i <= b; i++)//如果已分配区域的内存空间 》 0则可以展示信息if(fee[i][2] != 0)cout<<"作业名:"<<fee[i][0]<<"内存起始地址:"<<fee[i][1]<<"占用内存空间: "<<fee[i][2]<<endl;cout<<endl;cout<<"空闲区表为:"<<endl;for(int j = 0; j < num; j++)//如果空闲区内存空间 》 0,则可以展示信息if(idle[j][1] != 0)cout<<"起始地址:"<<idle[j][0]<<"连续内存空间:"<<idle[j][1]<<endl;cout<<endl;}
//一下是进程调度部分//PCB类(封装进程的信息)
class Pcb
{private:
public:// 进程idint pid;// 进程优先数int priority;// 要求运行时间int time;// 进程状态bool state = true;// //进程的就绪队列// queue<Pcb> readyQueue;//进程中作业的名称int name;//进程中作业所占内存空间int space;//进程中作业所选择的适应方法int method;Pcb();Pcb(int pid, int priority, int time);Pcb(int pid,int priority,int time,int name,int space,int method);~Pcb();//进程运行一个时间片void run();//状态置为结束void stateFalse();
};
//进程运行一个时间片
void Pcb::run()
{//进程每运行一个时间片,要求运行时间减少1,优先数减少1this->priority--;this->time--;
}//状态置为结束
void Pcb::stateFalse()
{//进程运行完成将状态置为结束this->state = false;
}Pcb::Pcb()
{}
//构造函数,在创建PCB时输入运行时间和优先级
Pcb::Pcb(int pid, int priority, int time)
{this->pid = pid;this->priority = priority;this->time = time;
}Pcb::~Pcb()
{
}//构造函数,用于作业进程调度Pcb::Pcb(int pid,int priority,int time,int name,int space,int method)
{ this->pid = pid;this->priority = priority;this->time = time;this->name = name;this->space = space;this->method = method;
}
//进程调度队列排序
queue<Pcb> queuesort(queue<Pcb> a)
{int size = a.size();Pcb list[size];Pcb tmp;for (int i = 0; i < size; i++){list[i] = a.front();a.pop();}for (int i = 0; i < size - 1; ++i){for (int j = size - 1; j > i; --j){if (list[j - 1].priority < list[j].priority){tmp = list[j - 1];list[j - 1] = list[j];list[j] = tmp;}}}for (int i = 0; i < size; i++){a.push(list[i]);}return a;
}int main(){init();int n;int priority, time = 1;int name,space;queue<Pcb> queuesort(queue<Pcb> a);// 进程就绪队列queue<Pcb> readyQueue;int sum;cout<<"1. 分配空间: 2. 回收空间:"<<endl;cin>>ch1;cout<<endl;if(ch1 == 1){cout<<"请输入进程作业个数"<<endl;cin>>sum;for(int i = 0 ; i < sum; i++){cout<<"请输入进程作业的优先级"<<endl;cin>>priority;cout<<"请输入要分配内存的作业名及占用内存大小:";cin>>name>>space;cout<<endl;cout<<"1. 最先适应法: 2. 最佳适应法: 3. 最坏适应法:"<<endl;cin>>ch2;cout<<endl;//创建Pcb对象Pcb newpcb(i, priority, time, name,space,ch2);//将该进程置入就绪队列readyQueue.push(newpcb);}while (!readyQueue.empty()){//先对队列中的进程进行排序,按优先级从大到小的顺序readyQueue = queuesort(readyQueue);if(readyQueue.front().method == 1){work[b][0] = readyQueue.front().name;work[b][1] = readyQueue.front().space;zuixian();fp();}else if(readyQueue.front().method == 2){work[b][0] = readyQueue.front().name;work[b][1] = readyQueue.front().space;zuijia();fp();}else if(readyQueue.front().method == 3){work[b][0] = readyQueue.front().name;work[b][1] = readyQueue.front().space;zuihuai();fp();}print();//取出就绪队列队首的进程运行readyQueue.front().run();// 如果该进程运行时间完成,则将其状态置为结束,且退出队列if (readyQueue.front().time <= 0){readyQueue.front().stateFalse();readyQueue.pop();}} }cout<<"输入要回收的作业名:"<<endl;cin>>n;huishou(n);
}

测试用例及测试结果



希望对各位小伙伴有所帮助呀

天津理工大学《操作系统》实验二,存储器的分配与回收算法实现,代码详解,保姆式注释讲解相关推荐

  1. 天津理工大学操作系统实验

    天津理工大学操作系统实验 处理机调度算法的实现 存储器的分配与回收算法 磁盘调度算法的实现 简单随便写的,一些是借鉴了网上的例子,进行了修改. 处理机调度算法的实现 1. 设定系统中有五个进程,每一个 ...

  2. 天津理工大学 计算机网络综合实验,天津理工大学计算机网络 实验二

    <天津理工大学计算机网络 实验二>由会员分享,可在线阅读,更多相关<天津理工大学计算机网络 实验二(6页珍藏版)>请在人人文库网上搜索. 1.实验报告学院(系)名称:计算机与通 ...

  3. 存储器的分配与回收算法实现_垃圾内存回收算法

    (给算法爱好者加星标,修炼编程内功) 来源:施懿民 https://zhuanlan.zhihu.com/p/20712073 常见的垃圾回收算法有引用计数法(Reference Counting). ...

  4. 删除计算机系学生的选课记录6,天津理工大学+数据库实验二.doc

    文档介绍: 实验报告学院(系)名称:计算机与通信工程学院姓名Touchkiss学号20125577专业计算机科学与技术班级2班实验项目实验二:复杂SQL数据操作课程名称数据库系统课程代码0668026 ...

  5. 天津理工大学 计算机网络综合实验,天津理工大学计算机网络实验二.pdf

    实验报告 学院(系)名称: 计算机与通信工程学院 姓名 学号 专业 计算机科学与技术 班级 实验名称 实验二:基于 TCP/UDP 的 Socket 编程 课程名称 计算机网络 课程代码 实验时间 实 ...

  6. 操作系统实验二:物理内存管理系统

    操作系统实验二:物理内存管理系统 一. 实验目的 二. 实验内容 三. 实验准备 [实验概述] [关键数据结构] [执行流程] 四. 实验步骤 (一) 练习0:填写已有实验 (二) 练习1:实现 fi ...

  7. 天津理工大学计算机项目管理实验四,天津理工大学计算机网络实验四

    <天津理工大学计算机网络实验四>由会员分享,可在线阅读,更多相关<天津理工大学计算机网络实验四(4页珍藏版)>请在人人文库网上搜索. 1.实验报告学院(系)名称:计算机与通信工 ...

  8. 操作系统实验四:C++实现独占设备的分配与回收算法模拟

    目录 一.实验要求 1.实验名称 2.实验目的 3.实验内容 二.实验图解 三.实验代码 四.实验数据 1.设备插入功能 2.回收程序功能 3.查找功能 一.实验要求 1.实验名称 独占设备的分配与回 ...

  9. 广州大学2020操作系统实验二:银行家算法

    相关资料 广州大学2020操作系统实验一:进程管理与进程通信 广州大学2020操作系统实验二:银行家算法 广州大学2020操作系统实验三:内存管理 广州大学2020操作系统实验四:文件系统 广州大学2 ...

最新文章

  1. 解压文件出错解决方法(invalid compressed data--format violated)
  2. python字符串、列表和文件对象总结
  3. Oracle 数据文件迁移
  4. 模版:线段树合并+线段树分裂
  5. 前端学习(2553):内容概述
  6. CPU占用率是什么?
  7. 复工后,汉堡薯条、奶茶“续命”又开始了
  8. (ACM模板)队列queue
  9. OpenCV遍历文件夹中所有图像
  10. python_迭代器、生成器
  11. 计算机中的字体文件夹在哪,字体文件夹,教您怎么找字体文件夹
  12. 从开源硬件到开放型工业控制器
  13. 人民币大写金额转换算法
  14. Ubuntu 重装显卡驱动(因内核升级导致失效后)
  15. 编写业务逻辑代码-清晰可维护是很重要的
  16. html圣诞节网页制作,圣诞节快乐——为你的网页添加一个可爱的HTML5圣诞节雪人!...
  17. ps4正在连接ea服务器,ps4极品飞车19连不上ea服务器 | 手游网游页游攻略大全
  18. springboot 整合 security(四) 方法级别权限控制 @resource,@secured,@preAuthorize
  19. 计算机开机按f1f2,电脑开机总是提示按f1 f2问题的解决办法
  20. python基础----文件处理

热门文章

  1. Android下拉刷新上拉加载控件,对所有View通用!
  2. 谷歌生物医学翻译软件_科研神器丨一个软件带你零基础阅读英文文献
  3. 【Hi3559AV100 Camera】Hi3559AV100 环境搭建
  4. 长知识了,mongo的时间居然这个样子
  5. HDU 威威猫系列故事——篮球梦
  6. OpenGL教程8(Bang翻译Delphi版)-如何制作立体透明效果 .
  7. SVM支持向量机的应用
  8. 手机物流详情页面模板.
  9. html 转换为jade,html转jade.htm
  10. 视频编码指标中的BD-BR/BD-rate和BD-PSNR的说明和计算(ExcelMatlab)