/Memory_Management

os课设2——内存管理

Primary LanguageC++

Memory_Management

os课设2——内存管理

项目需求

基本任务

假设初始态下,可用内存空间为640K,并有下列请求序列,请分别用首次适应算法和最佳适应算法进行内存块的分配和回收,并显示出每次分配和回收后的空闲分区链的情况来。

项目目的

  1. 学习相关数据结构、分配算法
  2. 加深对动态分区存储管理方式及其实现过程的理解。

功能分析

基于项目目的与项目需求,我们对本项目进行功能分析。

首先,我们需要在项目中添加作业,形成一个作业序列,因此我们需要输入作业名,作业大小,状态(申请或者释放),然后将其插入作业序列中。对于这个作业序列,我们要能够对其进行修改,所以我们要有删除序列里的一个作业与清空作业序列的功能;在要开始进行分配时,点击开始键,这时对序列的操作就要禁止,防止发生错误。我们通过点击“下一个”按钮来进行分配过程,分配完后,点击“清空”,就可以恢复到开始前的初始状态。

内存要有初始大小,因此我们要让用户能够自己定义内存大小,同时也要让用户能够选择两种不同的算法(最佳适应算法与首次适应算法)。

在修改作业序列以及分配的时候,我们要让用户能够实时看到目前的情况,因此项目中添加了五个窗口,有内存窗口,在上面可以实时看到各个作业占用内存的情况;有一个内存分区表,里面有两个窗口,所有分区窗口能看到在分配过程中,每个内存块的起始位置,中止位置与大小,空闲分区窗口能看到所有空闲内存块的起始位置,中止位置与大小;日志记录表详细记录了每一步内存的变化情况;作业需求表则显示了当前的作业序列。

由于项目需求中的相关规定,我们设置内存空间初始值为640K,并且设置了默认作业请求序列,可以一键导入。

算法设计

首次适应算法设计

空闲分区以地址递增的次序链接。分配内存时顺序查找,找到大小满足要求的第一个空闲分区。然后再按照作业的大小,从该分区中划出一块内存分配给请求者,余下的空闲分区仍留在空闲分区链中。该算法倾向于使用内存中低地址部分的空闲区,在高地址部分的空闲区很少被利用,从而保留了高地址部分的大空闲区。显然为以后到达的大作业分配大的内存空间创造了条件。但低地址部分不断被划分,留下许多难以利用、很小的空闲区,而每次查找又都从低地址部分开始,会增加查找的开销。

先判断当前要分配的作业的状态,有以下两种可能:

  1. 作业是申请状态。此时需要遍历内存分区列表,找到第一个空闲分区且该空闲分区的大小不小于要分配的作业大小。找到后在该空闲分区中划出与作业大小相同的块并放入作业,剩下部分(如果有)成为一个新的空闲分区。随后将原来的空闲分区从列表中删去,加入分配过作业的分区与新的空闲分区,并在日志中记录,更改该作业状态分配状态为“已分配”。如果遍历完也没有找到合适的空闲分区,就改该作业状态分配状态为“未分配”并存入等待列表。
  2. 作业是释放状态。此时同样遍历内存分区列表进行名称匹配,找到要释放的分区块。将其状态改为空闲状态,并且判断该分区的前后区块是否为空闲状态,如果是,就要进行合并成为一个大的空闲分区。结束后,再遍历等待列表,看释放后生成的空闲分区能不能满足其中的一些未被分配的作业,如果可以的话就进行分配,同时在等待列表中删除相应的数据。 操作结束后,将分区数据显示在空闲分区表与全部分区表中。

最佳适应算法设计

该算法总是把既能满足要求,又是最小的空闲分区分配给作业。为了加速查找,该算法要求将所有的空闲区按其大小排序后,以递增顺序形成一个空白链。这样每次找到的第一个满足要求的空闲区,必然是最优的。孤立地看,该算法似乎是最优的,但事实上并不一定。因为每次分配后剩余的空间一定是最小的,在存储器中将留下许多难以利用的小空闲区。同时每次分配后必须重新排序,这也带来了一定的开销。

先判断当前要分配的作业的状态,有以下两种可能:

  1. 作业是申请状态,此时先初始化最小合适空闲分区的大小为极大值,然后需要遍历内存分区列表,如果找到空闲分区且该空闲分区的大小不小于要分配的作业大小,就把它的大小与当前找到的最小合适空闲分区进行比较,如果它更小,就更新最小合适空闲分区为该分区。遍历结束后在该最小合适空闲分区中划出与作业大小相同的块并放入作业,剩下部分(如果有)成为一个新的空闲分区。随后将原来的空闲分区从列表中删去,加入分配过作业的分区与新的空闲分区,并在日志中记录,更改该作业状态分配状态为“已分配”。如果遍历完也没有找到合适的空闲分区,就改该作业状态分配状态为“未分配”并存入等待列表。
  2. 作业是释放状态。此时同样遍历内存分区列表进行名称匹配,找到要释放的分区块。将其状态改为空闲状态,并且判断该分区的前后区块是否为空闲状态,如果是,就要进行合并成为一个大的空闲分区。结束后,再遍历等待列表,看释放后生成的空闲分区能不能满足其中的一些未被分配的作业,如果可以的话就进行分配,同时在等待列表中删除相应的数据。 操作结束后,将分区数据显示在空闲分区表与全部分区表中。

操作说明

  1. 如果想在作业需求表中加入一条数据,就在系统对应位置输入作业名,大小与状态,然后点击插入。注意大小只能输入纯数字;并且同一作业名只能申请一次内存;释放作业内存时,该作业必须在之前申请过内存并且还没有释放;不能二次释放等等,一旦违反,系统会弹出警告信息。
  2. 点击“导入默认请求序列”按钮后,会自动清空作业需求表并加入默认序列。
  3. 如果要删除作业需求表中的一行数据,就在数字选择窗口选择行数后点击删除键,注意行数选择有误或者删除之后有释放操作的作业时,系统会弹出警报消息。
  4. “清空”按钮只会初始化作业分配状态,不会清空作业需求表。如果要清空该表请点击“清空作业表”。
  5. 在标题下方可以使用下拉控件选择合适的算法。
  6. 使用进度条可以选择内存的大小,并在下方显示。
  7. 点击开始键后,系统就进入内存分配模式。此时,内存大小选择,插入或删除作业需求表等操作都被禁止进行。
  8. 点击下一个,可以从作业需求表中调取下一个需求进行分配。如果到了最后一个,“下一个”按钮会变成不可点击状态。
  9. 点击清空键后,禁止进行的操作会被恢复,同时内存分区表和日志记录中的数据会被清理,同时初始化作业分配状态。
  10. 分配的实时情况可以通过下面的三张表和中间的内存分区可视化窗口来进行观察。