操作系统课程设计.docx
《操作系统课程设计.docx》由会员分享,可在线阅读,更多相关《操作系统课程设计.docx(31页珍藏版)》请在冰豆网上搜索。
操作系统课程设计
课程设计任务书
学生姓名:
专业班级:
指导教师:
工作单位:
计算机科学与技术学院
题目:
动态分区管理的主存分配模拟设计--最先适应法、最差适应法
初始条件:
1.预备内容:
阅读操作系统的内存管理章节内容,理解动态分区的思想,并体会各分配算法的具体实施方法。
2.实践准备:
掌握一种计算机高级语言的使用。
要求完成的主要任务:
(包括课程设计工作量及其技术要求,以及说明书撰写等具体要求)
1.采用指定算法模拟动态分区管理方式的主存分配。
能够处理以下的情形:
⑴随机出现的进程i申请jKB内存,程序能判断是否能分配,如果能分配,要求输出分配的首地址Faddress,并要求输出内存使用情况和空闲情况。
内存情况输出的格式为:
Faddress该分区的首地址;Eaddress该分区的尾地址
Len分区长度;Process如果使用,使用的进程号,否则为0
⑵主存分配函数实现寻找空闲区、空闲区表的修改、已分配区表的修改功能;
2.设计报告内容应说明:
⑴需求分析;
⑵功能设计(数据结构及模块说明);
⑶开发平台及源程序的主要部分;
⑷测试用例,运行结果与运行情况分析;
⑸自我评价与总结:
)你认为你完成的设计哪些地方做得比较好或比较出色;
)什么地方做得不太好,以后如何改正;
)从本设计得到的收获(在编写,调试,执行过程中的经验和教训);
)完成本题是否有其他方法(如果有,简要说明该方法);
)对实验题的评价和改进意见,请你推荐设计题目。
时间安排:
设计安排一周:
周1、周2:
完成程序分析及设计。
周2、周3:
完成程序调试及测试。
周4、周5:
验收、撰写课程设计报告。
(注意事项:
严禁抄袭,一旦发现,一律按0分记)
指导教师签名:
年月日
系主任(或责任教师)签名:
年月日
目录
封面......................................
(1)
课程设计任务书............................
(2)
1.需求分析................................(4)
2.功能设计................................(5)
2.1.数据结构..............................(5)
2.2.模块说明..............................(6)
2.2.1最先适应法(first-fit)................(6)
2.2.2最坏匹配法(worst-fit)................(8)
3.开发平台及源程序的主要部分..............(9)
4.测试用例,运行结果与运行情况分析........(16)
4.1.最先适应法.............................(16)
4.2最坏适应法.............................(19)
5.自我评价与总结..........................(23)
6.参考文献................................(24)
1.需求分析
在科技高速发展的今天,计算机早已成为人类的常用现代工具,每一个人都应该了解计算机,学会使用计算机,并用它来处理面临的事务。
对于一台完全无软件的计算机系统,即使功能再强,也必定是难于使用的。
所以在计算机上覆盖了OS后,便可获的一台功能显著使用极为方便的计算机。
因此操作系统是最重要的计算机系统软件,而进程调度是操作系统中最核心的内容。
存储器是计算机的重要组成部分,存储空间是操作系统管理的宝贵资源,虽然其容量在不断扩大,但仍然远远不能满足软件发展的需要。
对存储资源进行有效的管理,不仅关系到存储器的利用率,而且还对操作系统的性能和效率有很大的影响。
操作系统的存储管理的基本功能有:
存储分配、地址转换和存储保护、存储共享、存储扩充。
存储分配指为选中的多道运行的作业分配主存空间;地址转换是把逻辑地址空间中的用户程序通过静态重定位或动态重定位转换和映射到分给的物理地址空间中,以便用户程序的执行;存储保护指各道程序只能访问自己的存储区域,而不能互相干扰,以免其他程序受到有意或无意的破坏;存储共享指主存中的某些程序和数据可供不同用户进程共享。
最简单的单道系统中,一旦一个程序能装入主存,它将一直运行直到结束。
如果程序长度超出了主存的实际容量,可以通过覆盖和交换的技术获得解决。
更多的操作系统支持多个用户进程在主存同时执行,能满足多道程序设计需要的最简单的存储管理技术是分区方式,有分固定分区和可变分区。
可变分区的分配(如图
(1)所示)算法包括:
最先适应、下次适应、最佳适应、最坏适应和快速适应等分配算法。
图
(1)动态内存分配
采用分区方式管理存储器,每道程序总是要求占用主存的一个或几个连续的存储区域,主存中会产生许多碎片。
因此,有时为了接纳一个新的作业而往往要移动已在主存的信息,这不仅不方便,而且开销不小。
现代计算机都有某种虚存硬设备支持,简单也是常用的虚存是请求分页式虚存管理,于是允许把一个进程的页面存放到若干不相邻的主存页框中。
从搜索速度上看,最先适应算法具有最佳性能。
并且从回收过程来看,最先适应法也是最佳的。
它的另一个优点就是尽可能地利用了低地址空间。
从而保证高地址有较大的空闲区来放置要求内存过多的进程或作业。
最坏适应法是基于不留下碎片空闲区这一出发点的。
它选择最大的空闲区来满足用户要求,以期分配后的剩余部分仍能再分配。
本课程设计就是分析动态分区法,与固定分区法相比,动态分区法在作业执行前并不建立分区,分区的建立是在作业的处理过程中进行的。
且其大小可随作业或进程对内存的要求而改变分区的建立是在作业的处理过程中进行的。
且其大小可随作业或进程对内存的要求而改变。
这就改变了固定分区法中那种即使是小作业也要占据大分区的浪费现象,从而提高了内存的利用率。
2.功能设计
2.1数据结构
最先适应法和最差适应法都采取了相同的数据结构:
设计了两个数据结构:
进程类process:
classprocess
{
public:
process(void);
intgetnumber();
intgetsize();
~process(void);
private:
inti;//进程号
intsize;//进程大小
};
process:
:
process(void)
{
i=nrand(50);
size=nrand(110)+1;
}
进程号是0~49的随机数,进程大小是1~110的随机数。
进程的图形类似图
(2)所示:
图
(2)进程的结构图
分区类memory:
classmemory
{
public:
memory(void);
memory(inta1,inta2,inta3,inta4);
intgetnumber();
voidsetnumber(intz);
intgetprocessnumber();
voidsetprocessnumber(intx);
intgetFaddress();
voidsetFaddress(intt);
intgetlen();
voidsetlen(inty);
~memory(void);
private:
intnumber;
intprocessnumber;
intFaddress;
intlen;
};
分区单元类memory里有4个数据成员,分别为:
number(分区号)、processnumber(此分区内的进程号)、Faddress(分区的首地址)、len(分区的长度),由此可得分区尾地址Eaddress(分区的尾地址)。
内存分配表的图类似与图(3)所示:
图(3)内存使用情况
2.2模块说明
2.2.1最先适应法(first-fit)
按分区起始地址的递增次序,从头查找,找到符合要求的第一个分区。
该算法的分配和释放的时间性能较好,一旦找到大于或等于所要求内存长度的分区,则结束探索。
for(inti=1;i!
=50;i++)
{
processpr;
intp=table[i-1].getFaddress()+pr.getsize();
intn=nrand(100);
intj=nrand(3);
table[i]=memory(i+1,(i+1)*j,p,n);
}
采用随机产生的进程processpr来初始化内存,一共产生了50个进程他们将对内存的所有内存单元进行初始化。
当j=0时,则(i+1)*j=0,即此内存单元的进程号为“0”,按任务书的标准这代表该内存单元空闲。
由于j=nrand(3),故j=0的概率为33.3%。
即内存中有33.3%的单元是空闲的。
cout<<"区号进程号首地址尾地址长度"<for(inti=0;i!
=50;i++)
{
cout<
<<'\t'<
+table[i].getlen()<<'\t'<
}
该语句是输出初始化后内存单元的使用情况。
choice=="create"模块是进行创建一个随机进程,并按照最先适应法的要求,对内存单元进行查找。
当第一个找到满足要求的内存单元即用该内存单元存放该进程。
并建立一个内存单元的对象memorymtemp用于保存该内存单元除了进程部分所剩下的内存单元,并将该内存单元的剩余部分仍保留在内存中。
该模块完成的功能如图(4)所示:
图(4)进程进入内存
choice="inquire"模块对内存单元的使用情况输出。
choice="empty"模块是将内存单元中进程号processnumber=0的内存单元全部保存到空闲区表emptytab中,并将该表中的内容输出。
choice="full"模块是将内存单元中进程号processnumber!
=0的内存单元全部保存到已分配区表fulltab中,并将该表中的内容输出。
最先适应法流程如图(5)所示:
图(5)最先适应算法流程
2.2.2最坏匹配法(worst-fit)
按分区大小的递减次序,从头查找,找到符合要求的第一个分区。
找到最大的空闲分区。
大部分模块和最先适应法是相同的。
现只对create模块和empty模块说明。
choice="create"模块创建一个进程,然后将内存单元的空闲单元保存到容器emptytab1中,并对emptytab1按内存单元从大到小进行排列,然后将进程的大小size和空闲区表emptytab1中的第一个内存单元比较,当size小于第一个内存单元的大小,则进行分配,并建立一个内存单元的对象memorymtemp用于保存该内存单元除了进程部分所剩下的内存单元,并将该内存单元的剩余部分仍保留在内存中。
当size大于第一个内存单元的大小,则输出"超出可用表第一项长度,无法分配!
"。
choice="empty"模块是将内存单元的空闲单元保存到容器emptytab中,并对empty按内存单元从大小进行排列,并将空闲区表输出。
这两个模块实现的功能如图(6)所示:
图(6)最差适应法内存分配
3.开发平台及源程序的主要部分
3.1开发平台
采用visualstudio2008C++的控制台应用程序进行开发。
3.2源程序的主要部分
3.2.1进程类的头文件与实现
//进程类process.h
#include
classprocess
{
public:
process(void);
intgetnumber();
intgetsize();
~process(void);
private:
inti;//进程号
intsize;//进程大小
};
intnrand(intn);
//进程类process.cpp
#include"process.h"
#include
usingstd:
:
domain_error;
process:
:
process(void)
{
i=nrand(50);
size=nrand(110)+1;
}
process:
:
~process(void)
{
}
intprocess:
:
getnumber()
{
returni;
}
intprocess:
:
getsize()
{
returnsize;
}
intnrand(intn)
{
if(n<=0||n>RAND_MAX)
throwdomain_error("Argumenttonrandisoutofrange");
constintbucket_size=RAND_MAX/n;
intr;
dor=rand();
while(r>=n);
returnr;
}
3.2.2分区类的头文件与实现
//分区类memory.h
#pragmaonce
#include
classmemory
{
public:
memory(void);
memory(inta1,inta2,inta3,inta4);
intgetnumber();
voidsetnumber(intz);//设置该分区的区号
intgetprocessnumber();
voidsetprocessnumber(intx);//设置占用该分区的进程号
intgetFaddress();
voidsetFaddress(intt);//设置该分区的首地址
intgetlen();
voidsetlen(inty);
~memory(void);
private:
intnumber;
intprocessnumber;
intFaddress;
intlen;
};
//分区类memory.cpp
#include"memory.h"
memory:
:
memory(void)
{
}
memory:
:
memory(inta1,inta2,inta3,inta4)
{
number=a1;
processnumber=a2;
Faddress=a3;
len=a4;
}
intmemory:
:
getnumber()
{
returnnumber;
}
voidmemory:
:
setnumber(intz)
{
number=z;
}
intmemory:
:
getprocessnumber()
{
returnprocessnumber;
}
voidmemory:
:
setprocessnumber(intx)
{
processnumber=x;
}
intmemory:
:
getFaddress()
{
returnFaddress;
}
voidmemory:
:
setFaddress(intt)
{
Faddress=t;
}
intmemory:
:
getlen()
{
returnlen;
}
voidmemory:
:
setlen(inty)
{
len=y;
}
memory:
:
~memory(void)
{
}
3.2.3最先适应法
/*最先适应法,先创建一个随机进程p,再逐个遍历内存单元,如果发现该内
*存单元是空闲的并且它的大小比进程申请长度大,则对它进行分配。
*/
//create模块
if(choice=="create")
{
processp;
cout<<"创建的进程号为:
"<
"<
for(vector:
:
iteratoriter=distable.begin();iter!
=distable.end();++iter)
{
if(iter->getprocessnumber()==0&&iter->getlen()>=p.getsize())
{
iter->setprocessnumber(p.getnumber());//修改该内存单元的进程号
inttemp2=iter->getlen();//将内存单元的长度保存
iter->setlen(p.getsize());//将内存单元的长度改为进程申请的长度
memorymtemp;//临时对象保存剩余内存单元
inttemp1=iter->getnumber();//保存内存单元的分区号
inttemp=iter->getFaddress();//保存内存单元的首地址
mtemp.setnumber(temp1);//设置临时对象的分区号
mtemp.setprocessnumber(0);//设置临时单元的进程号
mtemp.setFaddress(temp+p.getsize());//设置临时单元的首地址
mtemp.setlen(temp2-p.getsize());//设置临时单元的长度
++iter;
if(mtemp.getlen()!
=0)//如果临时单元长度不为零
{
distable.insert(iter,mtemp);//将临时单元保存到内存中
}
cout<<"分配的区号:
"<"<break;
}
if(++iter==distable.end())//如果已经到了内存中最后一个内存单元
{
cout<<"超出最大空闲区,无法分配!
"<}
--iter;
}
}
/*inqurie模块对内存单元情况进行输出
*/
if(choice=="inquire")
{
cout<<"区号进程号首地址尾地址长度"<for(vector:
:
iteratoriter=distable.begin();iter!
=distable.end();++iter)
{
cout<getnumber()<<'\t'<getprocessnumber()
<<'\t'<getFaddress()<<'\t'<getFaddress()+iter->getlen()<<'\t'<getlen()<}
}
/*full模块对进程号不为零的单元进行输出
*/
if(choice=="full")
{
vectorfulltab;
for(vector:
:
iteratoriter=distable.begin();iter!
=distable.end();++iter)
{
if(iter->getprocessnumber()!
=0)
{
fulltab.push_back(*iter);
}
}
cout<<"已分配区表"<cout<<"区号进程号首地址尾地址长度"<for(vector:
:
iteratoriter=fulltab.begin();iter!
=fulltab.end();++iter)
{
cout<getnumber()<<'\t'<getprocessnumber()
<<'\t'<getFaddress()<<'\t'<getFaddress()+iter->getlen()<<'\t'<getlen()<}
}
3.2.4最坏适应法
/*create模块先将processnumber==0的分区保存到空闲区表emptytab1中,然*后对emptytab1按长度从大到小排列,再将内存单元中是空闲区的和emptytab1*表中的第一个元素分配给进程p
*/
if(choice=="create")
{
processp;
cout<<"创建的进程号为:
"<
"<
vectoremptytab1;
for(vector:
:
iteratoriter=distable.begin();iter!
=distable.end();++iter)
{
if(iter->getprocessnumber()==0)
{
emptytab1.push_back(*iter);
}
}
sort(emptytab1.begin(),emptytab1.end(),compare);
for(vector:
:
iteratoriter=distable.begin();iter!
=distable.end();++iter)
{
if(iter->getprocessnumber()==0&&iter->getnumber()==emptytab1.begin()->getnumber()&&emptytab1.begin()->getlen()>=p.getsize())
{
iter->setprocessnumber(p.getnumber());
inttemp2=iter->getlen();
iter->setlen(p.getsize());
memorymtemp;
inttemp1=iter->getnumber();
inttemp=iter->getFaddress();
mtemp.setnumber(temp1);
mtemp.setprocessnumber(0);
mtemp.setFaddress(temp+p.getsize());
mtemp.setlen(temp2-p.getsize());
++iter;
if(mtemp.getlen()!
=0)
{
distable.insert(iter,mtemp);
}
展开阅读全文
相关搜索