操作系统原理 实验2 《Allocation & Reclaim》
一、实验目的
帮助了解在不同的存储管理方式下,应怎样实现主存空间的分配和回收。
二、实验内容
1、主存储器空间的分配和回收:
2、在可变分区管理方式下,采用最先适应算法实现主存空间的分配和回收。
三、实验方法
1、自行假设主存空间大小,预设操作系统所占大小并构造未分分区表;
表目内容:起址、长度、状态(未分/空表目)
2、结合实验一,PCB增加为:
{PID,要求运行时间,优先权,状态,所需主存大小,主存起始位置,PCB指针}
3、采用最先适应算法分配主存空间;
4、进程完成后,回收主存,并与相邻空闲分区合并。
四、实验步骤
1、选定程序开发环境
Qt Creator 4.2.1(Qt 5.8.0)
图形化界面编程使用的编程语言:C++
2、明确功能(需求分析)
相比实验一增加的功能:
构造主存占用情况的展示,构造未分分区表的展示,进程进入内存时自动分配空间,进程退出内存时完成内存释放与合并。(选:内存进入时符合条件则进行紧缩)。
3、设计数据结构
(1) 使用一个整型数组代表内存空间,大小暂定32KB,每一个数组元素空间即为1KB的内存单元空间,0表示未被占用,1表示已经被占用;
(2) 内存的使用情况、未分分区表均通过界面上的QTableWiget
控件进行展示. 为了展示效果,使用不同颜色的表格单元区分新加入的进程、本就在内存中的进程以及常驻内存的操作系统这三种内存占用;
(3) 未分分区表中的记录由于数目不确定,因此使用QList容器进行存储;但是因为每条记录有三个属性,故将记录封装成一个结构体,QList
容器用于保存对应的结构体指针;
(4) 由于最近在浏览Qt的相关博客时发现了部分博主自定义了一些有趣的组件,因此打算写个类似仪表盘的自定义组件来展示内存占用百分比。
4、设计各类操作(写成类内函数封装实现)
(1) 在widget
类中添加功能:
- 初始化:内存展示表格、未分分区表展示表格、未分分区表容器;
- 刷新:未分分区表展示表格、内存展示表格;
- 对未分分区表的容器进行按照起址/空间排序;
- 检测:是否有未分分区空间大小满足、总剩余空间大小是否满足;
- 为新进内存的进程分配内存地址(根据不同内存分配策略),修改内存占用;
- 更新:所有进程在内存区域显示的颜色状态,内存占用百分比展示;
- 依照不同算法返回合适的未分分区表记录在容器中的下标;
- 进程出内存后内存回收:修改代表内存空间的数组,修改未分分区表,修改未分分区表展示表格,修改数组占用展示表格,修改内存展示仪表盘状态;
- 进程出内存后未分分区记录合并:符合条件则修改未分分区表,修改未分分区表展示表格;
- (选)作业在进入内存进行内存分配时,加一层判断,如果总剩余空间大小满足条件,则进行内存紧缩:修改代表内存空间的数组,修改未分分区表,修改未分分区表展示表格,修改数组占用展示表格,修改内存展示仪表盘状态。
(2) 内存展示仪表盘(Passrate
类)
- 重绘事件:触发界面重绘;
- 根据传入的值的参数更新展示的值,触发事件重绘;
- 绘制:最外围的线、中心最外层背景、中心文字背景、中心文字
5、确定关键策略
(1) 三种内存分配算法
最先适应分配:
将未分分区表的存储容器中的指针按照内存起址大小从小到大排序,利用for循环从下标0开始遍历,找到第一个目标元素(即该区域内存宽度大于等于目标进程需要的内存大小)就马上返回其下标,然后退出;
最优适应分配:
将未分分区表的存储容器中的指针按照空间大小从小到大排序,利用for循环从下标0开始遍历,找到第一个目标元素(即该区域内存宽度大于等于目标进程需要的内存大小)就马上返回其下标,然后退出;
最差适应分配:
将未分分区表的存储容器中的指针按照空间大小从小到大排序,如果容器最后一个指针对应的记录的内存宽度大于等于目标进程需要的内存大小则返回其下标,然后退出;。
(2) 内存分配算法
进程即将进主存时,
- 如果总剩余空间不够:拒绝进程进入主存,打印输出拒绝信息;
- 如果总剩余空间足够:
如果按照上述三种算法能找到适合的未分分区记录下标,则将进程加入主存,修改相关主存信息
如果按照上述三种算法未能找到适合的未分分区记录下标,则进行内存紧缩后再尝试分配;如果再分配失败则打印输出错误信息。
6、编写程序实现上述功能,并进行界面的优化整理
五、实验结论
最优适应分配算法的效率并不高(不仅要进行排序,还需要遍历),但是可以节省大空间,保证后来的进程尽量有空间可用;最差适应分配算法的分配效率应该是最高的,但是对空间的浪费比较多,不能保证后来的进程(特别是内存占用较大的进程)的空间分配;而最先适应分配算法应该是处于二者之间。三种算法各有优劣势,需要根据系统的具体分配情况斟酌考虑使用。
六、实验小结
本次实验,通过展示未分分区表和主存32KB空间的占用情况,使得自己在直观上更加理解了三种分配算法的不同(因为事先就决定了新加入的进程颜色要有区别,所以新加入的进程进入了哪块内存空间很明显,然后是未分分区表的数值、记录条数的变化也比较明显);其次是内存合并算法,其实可以分两种方式实现:一是遍历整个未分分区表,相邻记录之间符合条件则进行合并;二是直接在该记录的下标上下相邻记录之间进行判定,符合条件则进行合并,显然前者比较潦撇(代码容易写),后者效率较高。最后是紧缩算法,需要获取总内存剩余空间,然后删除所有未分分区表记录后新加一条记录,这是对未分分区表的操作;紧缩还包含程序自身的内存浮动:将所有在内存中的进程组成集合,按照内存起址排序,然后结合占用空间将它们首尾相接,最后更新各个容器,总之实现起来还比较繁琐,需要详细的事先规划。
展现: