操作系统课程设计作业.docx
《操作系统课程设计作业.docx》由会员分享,可在线阅读,更多相关《操作系统课程设计作业.docx(19页珍藏版)》请在冰豆网上搜索。
操作系统课程设计作业
《操作系统》课程设计
论文题目:
连续动态分区内存管理模拟实现
所在班级:
XXXXXX班
学生学号:
0310XXXXX
学生姓名:
XXX
任课教师:
****老师
完成日期:
2012年**月**日
目录
《操作系统》课程设计1
目录2
课程设计目的和内容:
3
系统分析设计:
3
第一章:
对内存管理的相关理论的了解3
内存管理概念:
3
虚拟内存的引出:
3
内存管理的必要性:
4
实现动态分区需要的数据结构:
4
第二章:
实现连续动态分区内存管理方式4
1、『单一连续分配』4
2、『固定分区分配』5
3、『动态分区分配』5
4、『动态重定位分区分配』5
可变分区存储管理分析:
5
第三章:
分析并实现四种内存分配算法6
如何分配空闲内存:
6
第四章:
回收算法的实现14
可变分区的回收:
14
可变分区方式的内存回收流程图15
实现分区存储管理的内存回收算法16
当碎片产生时,进行碎片的拼接18
学习心得和小结:
19
参考文献:
20
连续动态分区内存管理模拟实现
课程设计目的和内容:
理解内存管理的相关理论,掌握连续动态分区内存管理的理论;通过对实际问题的编程实现,获得实际应用和编程能力。
编写程序实现连续动态分区内存管理方式,该程序管理一块虚拟内存,实现内存分配和回收功能。
分析并实现四种内存分配算法,即首次适应算法,循环首次适应算法,最佳适应算法,最坏适应算法。
内存分配算法和回收算法的实现。
系统分析设计:
第1章:
对内存管理的相关理论的了解
内存管理概念:
内存管理,是指软件运行时对计算机内存资源的分配和使用的技术。
其最主要的目的是如何高效,快速的分配,并且在适当的时候释放和回收内存资源。
内存不是预先划分好的,而是在系统运行的过程中建立分区.当作业装入主存时,根据作业所需要的主存容量查看是否有足够的主存空间,若有则按需要分割一个分区给该作业;否则令该作业等待.分区长度不固定,分区个数不固定。
这种存储管理的方法克服了固定分区严重浪费主存的问题,提高了主存资源的利用率。
虚拟内存的引出:
虚拟内存是内存管理技术的一个极其实用的创新。
它是一段程序(由操作系统调度),持续监控着所有物理内存中的代码段、数据段,并保证他们在运行中的效率以及可靠性,对于每个用户层(user-level)的进程分配一段虚拟内存空间。
当进程建立时,不需要在物理内存件之间搬移数据,数据储存于磁盘内的虚拟内存空间,也不需要为该进程去配置主内存空间,只有当该进程被被调用的时候才会被加载到主内存。
内存管理的必要性:
内存管理对于编写出高效率的Windows程序是非常重要的,这是因为Windows是多任务系统,它的内存管理和单任务的DOS相比有很大的差异。
DOS是单任务操作系统,应用程序分配到内存后,如果它不主动释放,系统是不会对它作任何改变的;但Windows却不然,它在同一时刻可能有多个应用程序共享内存,有时为了使某个任务更好地执行,Windows系统可能会对其它任务分配的内存进行移动,甚至删除。
因此,我们在Windows应用程序中使用内存时,要遵循Windows内存管理的一些约定,以尽量提高Windows内存的利用率。
实现动态分区需要的数据结构:
在动态分区存储管理中,要有相应的数据结构来登记空闲区信息,它包括空闲区的大小和位置。
不同系统根据设计要求采用不同的结构。
常用的有表结构和链结构。
系统还要设置了等待分区队列,当系统中无空闲区或无满足要求的空闲区时,则把申请者送入等待队列中,等待别的进程释放内存之后再唤醒队列中的进程。
第2章:
实现连续动态分区内存管理方式
连续分配方式,是指为一个用户程序分配一个连续的内存空间,该连续内存空间指的的是物理内存。
下面介绍连续分配的四种方式。
1、『单一连续分配』
我们把内存(此时指的是内存条)分为系统内存区和用户区两部分,系统区供OS使用,用户区供用户使用,单一连续分配,就是把用户区当成了一个整体用,所以,该内存管理方式只适用于单用户单任务的操作系统。
2、『固定分区分配』
固定分区的思想:
把用户区提前分成固定大小的几个整体,每个整体都可以用来装入一个作业。
我们在划分用户区时,可以采用分区大小相等和分区大小不相等的方式划分,为了方便操作系统把相应的内存分给某个程序,因此,我们通常将分区按大小进行排队,并为之建立一张分区使用表,表中内容为:
每个分区的起始位置、大小及状态(是否分配)。
此分区方式可以实现多道程序的同时运行,但是,由于每个分区的大小是固定,必然会造成存储空间的浪费。
3、『动态分区分配』
动态分区分配的思想:
程序在装入内存中时,需要多少内存,我就给他多少内存。
一、怎么记录物理上不相连的内存?
采用这种分区方式,刚开始的时候,用户内存是一整块,但是,不断打开程序和关闭程序后,就会出现一块一块的内存,那么我们应该怎样管理这种情况呢?
我们采用某种数据类型来记录这些空闲的内存块,常用的数据结构类型有空闲分区表和空闲分区链,。
闲分区和固定分区的表的原理是一样的,只不过这种表的灵活更强;空闲分区链是在物理上不相邻的空闲空间的始尾写上了他的前一个块的地址和后一个块的地址,它还存储了其他的用于控制分区分配的信息。
4、『动态重定位分区分配』
其中心思想是,把不同程序,且在内存中地址不连续的想法让他们连续。
举例:
程序A、B,在内存中的位置不连续,即:
A和B中间有空闲内存,我就把B和那部分的空闲区对换,为了实现改过程序我们增加了一个硬件——重定位寄存器。
(虽然这种分区非常的好,但是,要真正的实现起来需要为此付出很大的开销,为了解决这个问题,人们有发明了一种分配方式——分页)
可变分区存储管理分析:
优点:
1.有助于多道程序设计
2.不需过多硬件,仅需界地址寄存器用于存储保护
3.所采用的算法都比较简单,易于实现
缺点:
1.碎片问题
由于空闲区的大小与申请内存的大小相等的情况是很少的,绝大多数情况是从一个空闲区中切去一块,剩下的部分作为一个空闲区仍留在空闲区表中,随着时间的推移,空闲区的发展趋势是越来越小,直至不能满足任何用户要求。
这种不能被任何用户使用的极小的空闲区称为碎片。
碎片的出现造成了存储空间的浪费。
2.分区大小受主存容量限制,无法扩充主存容量。
第3章:
分析并实现四种内存分配算法
如何分配空闲内存:
我们采用了一些分区算法,这些算法主要是针对的是存在了不连续的分区块的以下简单介绍一下。
【首次适应算法】:
分配:
当进程申请大小为SIZE的内存时,系统顺序查找空闲区表(链),直到找到容量满足要求(≥SIZE)的空闲区为止。
从该空闲区中划出大小为SIZE的分区分配给进程,余下的部分仍作为一个空闲区,但要修改其首址和大小。
优点:
这种算法是尽可能地利用低地址部分的空闲区,而尽量地保证高地址部分的大空闲区,有利于大作业的装入。
缺点:
主存低地址和高地址分区利用不均衡。
在低地址部分,集中了许多非常小的空闲区(碎片),降低了主存的利用率。
首次适应算法实现代码:
StatusFirst_fit(intrequest)
{
//为申请作业开辟新空间且初始化
DuLinkListtemp=(DuLinkList)malloc(sizeof(DuLNode));
temp->data.size=request;
temp->data.state=Busy;
DuLNode*p=block_first->next;
while(p)
{
if(p->data.state==Free&&p->data.size==request)
{//有大小恰好合适的空闲块
p->data.state=Busy;
returnOK;
break;
}
if(p->data.state==Free&&p->data.size>request)
{//有空闲块能满足需求且有剩余
temp->prior=p->prior;
temp->next=p;
temp->data.address=p->data.address;
p->prior->next=temp;
p->prior=temp;
p->data.address=temp->data.address+temp->data.size;
p->data.size-=request;
returnOK;
break;
}
p=p->next;
}
returnERROR;
}
【下次适应分配算法】:
首次适应算法的变种。
总是从空闲区上次扫描结束处顺序查找空闲区表(链),直到找到第一个满足容量要求的空闲区为止,分割一部分给作业,剩余部分仍作为空闲区。
下次适应分配算法实现代码:
voidNF_Assign(unsignedsize)/*循环首次适应算法的分配*/
{
LN*p,*t,*s;
p=find;
if(fsize<=0)
{
printf("系统已无可用空间\n");
return;
}
elseif(size>fsize)
{
printf("系统空间不足!
分配不成功\n");
return;
}
elseif(size<=0)
{
printf("大小不正确!
\n");
}
do
{
if(size>p->size)
{
p=p->next;
if(p==find)
{
printf("没有足够大的空闲区分配!
分配不成功\n");break;
}
}
else
{
p->size-=size;
p->m_addr+=size;
fsize-=size;
find=p->next;
if(p->size==0)
{
t=getpch(LN);
t=p->next;
t->front=p->front;
(t->front)->next=t;
n--;
if(p==L){L=t;}
free(p);
find=t;
}
printf("\n分配成功!
\n");
break;
}
}while
(1);
}//endofNF_Assign
【最佳适应算法】:
分配:
空闲区按容量递增的次序排列。
当进程申请存储空间,系统顺序查找空闲区表(链),直到找到第一个满足容量要求的空闲区为止。
采用最优适应算法选中的空闲区是满足容量要求的最小空闲区。
优点:
选中的空闲区是满足容量要求的最小空闲区,而不致于毁掉较大的空闲区。
缺点:
空闲区的大小一般与申请分区大小不相等,因此将其一分为二,留下来的空闲区一般情况下是很小的,以致无法使用。
随着时间的推移,系统中的小空闲区会越来越多,从而造成存储空间的浪费。
最佳适应算法实现代码:
StatusBest_fit(intrequest)
{
intch;//记录最小剩余空间
DuLinkListtemp=(DuLinkList)malloc(sizeof(DuLNode));
temp->data.size=request;
temp->data.state=Busy;
DuLNode*p=block_first->next;
DuLNode*q=NULL;//记录最佳插入位置
while(p)//初始化最小空间和最佳位置
{
if(p->data.state==Free&&(p->data.size>=request))
{
if(q==NULL)
{
q=p;
ch=p->data.size-request;
}
elseif(q->data.size>p->data.size)
{
q=p;
ch=p->data.size-request;
}
}
p=p->next;
}
if(q==NULL)returnERROR;//没有找到空闲块
elseif(q->data.size==request)
{
q->data.state=Busy;
returnOK;
}
else
{
temp->prior=q->prior;
temp->next=q;
temp->data.address=q->data.address;
q->prior->next=temp;
q->prior=temp;
q->data.address+=request;
q->data.size=ch;
returnOK;
}
returnOK;
}
【最坏适应算法】:
为了克服最佳适应算法把空闲区切割得太小的缺点,人们提出了一种最坏适应算法,即每次分配时,总是将最大的空闲区切去一部分分配给请求者,剩余的部分仍是一个较大的空闲区。
避免了空闲区越分越小的问题。
要求空闲区按容量递减的顺序排列。
分配:
进程申请存储区时,检查空闲区表(链)的第一个空闲区的大小是否满足要求,若不满足则令进程等待;若满足则从该空闲区中分配一部分存储区给用户,剩下的部分仍作为空闲区。
最坏适应算法实现代码:
StatusWorst_fit(intrequest)
{
intch;//记录最大剩余空间
DuLinkListtemp=(DuLinkList)malloc(sizeof(DuLNode));
temp->data.size=request;
temp->data.state=Busy;
DuLNode*p=block_first->next;
DuLNode*q=NULL;//记录最佳插入位置
while(p)//初始化最大空间和最佳位置
{
if(p->data.state==Free&&(p->data.size>=request))
{
if(q==NULL)
{
q=p;
ch=p->data.size-request;
}
elseif(q->data.sizedata.size)
{
q=p;
ch=p->data.size-request;
}
}
p=p->next;
}
if(q==NULL)returnERROR;//没有找到空闲块
elseif(q->data.size==request)
{
q->data.state=Busy;
returnOK;
}
else
{
temp->prior=q->prior;
temp->next=q;
temp->data.address=q->data.address;
q->prior->next=temp;
q->prior=temp;
q->data.address+=request;
q->data.size=ch;
returnOK;
}
returnOK;
}
第4章:
回收算法的实现
可变分区的回收:
当某个进程释放某存储区时,系统首先检查释放区是否与系统中的空闲区相邻,若相邻则把释放区合并到相邻的空闲区中去,否则把释放区作为一个空闲区插入到空闲区表的适当位置。
(a)释放区与前空闲区相邻:
将释放区与前空闲区合并为一个空闲区。
其首址仍为前空闲区首址,大小为释放区大小与空闲区大小之和。
(b)释放区与后空闲区相邻:
则把释放区合并到后空闲,首地址为释放区首地址,大小为二者大小之和。
(c)释放区与前后两个空闲区相邻:
将这三个区合为一个空闲区,其首址为前空闲区首址,大小为这三个区大小之和,并取消原后空闲区表目。
(d)释放区不与任何空闲区相邻:
将释放区作为一个空闲区,将其大小和首址插入到空闲区表的适当位置。
可变分区方式的内存回收流程图
实现分区存储管理的内存回收算法
voidinsertFreeNode(structfreeList**empty,intstartAddress,intsize)
插入回收的空节点分区,处理回收分区与空闲分区的四种邻接关系。
{
structfreeList*p,*q,*r;
for(p=*empty;p->next;p=p->next);
/*处理链表尾部的邻接情况*/
if(p==*empty||p->startAddress+p->size/*与尾部不相邻*/
{
makeFreeNode(&r,startAddress,size);
/*通过r指针返回创建的空闲节点*/
r->next=p->next;/*插入独立的空闲节点*/
p->next=r;
return;
}
if(p->startAddress+p->size==startAddress)/*与尾部上邻*/
{
p->size+=size;/*合并尾部节点*/
return;
}
q=(*empty)->next;/*处理链表首节点的邻接情况*/
if(startAddress+size==q->startAddress)/*与首节点下邻*/
{
q->startAddress=startAddress;/*合并首节点*/
q->size+=size;
}
elseif(startAddress+sizestartAddress)
/*与首节点不相邻*/
{
makeFreeNode(&r,startAddress,size);
r->next=(*empty)->next;
(*empty)->next=r;
}
else
{/*处理链表中间的邻接情况*/
while(q->next&&q->startAddress{
p=q;
q=q->next;
}
if(p->startAddress+p->size==startAddress&&\
q->startAddress==startAddress+size)
/*上下邻,合并节点*/
{
p->size+=size+q->size;
p->next=q->next;
free(q);/*删除多余节点*/
}
elseif(p->startAddress+p->size==startAddress&&\
q->startAddress!
=startAddress+size)
/*上邻,增加节点的大小*/
{
p->size+=size;
}
elseif(p->startAddress+p->size!
=startAddress&&\
q->startAddress==startAddress+size)/*下邻*/
{
q->startAddress=startAddress;/*修改节点起始地址*/
q->size+=size;/*修改节点的大小*/
}
else
{/*上下不相邻*/
makeFreeNode(&r,startAddress,size);
r->next=p->next;
p->next=r;
}
}
}
当碎片产生时,进行碎片的拼接
voidmoveFragment(structjobList*jobs,structfreeList**empty,structusedList**used)
{
intsize,status;
structusedList*p;
intaddress=memoryStartAddress;
/*全局变量,初始化时分配存储空间始址*/
if((*empty)->next==NULL)/*空闲分区链表为空,提示并返回*/
{
printf("\nThememorywasusedoutatall.\nMaybeyoushouldfinishsomejobsfirstorpressanykeytotryagain!
");
getch();
return;
}
for(p=(*used)->next;p;p=p->next)
/*循环的修改占用分区的始址*/
{
p->startAddress=address;
getJobInfo(jobs,p->jobID,&size,&status);
/*由作业ID获得作业大小*/
address+=size;
}
(*empty)->next->startAddress=address;
/*修改空闲分区的首节点始址、大小*/
(*empty)->next->size=memorySize-(address-memoryStartAddress);
(*empty)->next->next=NULL;/*删除首节点后的所有节点*/
}
学习心得和小结:
通过学习这门课程,特别是搜集和整理本文材料,编写这篇论文的时候,我对连续动态分区内存管理模拟实现的了解更加深入,无论是对其原理还是概念都比以前要清晰,对其也由以前的零散学习到现在的综合地系统地了解。
操作系统内部原理对我自己学习来说是十分复杂的,所以这篇论文的编写确实给我带来了很大的挑战。
为了完成这篇课程设计,我搜集了许多资料,进行阅读理解,然后整合,对自己确实提供了很大的帮助。
让自己对这门课程的理解更加深刻,也让自己对操作系统内部原理由原来的敬而远之到现在的理解和探索。
学习了其原理,对自己朝着这方面的发展也更加有作用。
对四种内存分配算法以前只是了解其运行机理,理论上的认识还比较好,可是从未做过算法编程模拟,因此对此一直都是浮于表面,没有沉下心来去钻研,这次借着这个机会我进行了尝试,效果还可以。
总的来说,这次的课程设计写作和研究对自己帮助很大,课程设计写作的不是很好,希望老师批评指正。