操作系统实验内存分配(链表实现)
- 格式:doc
- 大小:46.00 KB
- 文档页数:8
实验报告(五)内存分配一、实验目的通过学习Minix操作系统的内存分配,加深理解操作系统内存管理的相关概念和原理。
二、准备工作注:如果熟悉准备工作内容,可忽略。
1、练习使用vi编辑器vi编辑器具有两种模式(1)命令模式通过键盘左上角ESC键进入,在该模式下可以使用编辑命令。
删除一行(连续键入两个d);删除光标处的字符(小写x);在当前光标前插入(i);在当前光标后插入(a);保存(shift+冒号,再键入w);退出编辑器(shift+冒号,再键入q);保存并且退出(shift+冒号,再键入wq);(2)编辑模式在命令模式下,通过在当前光标前插入(i)或在当前光标后插入(a),进入编辑模式。
通过键盘左上角ESC键切换到命令模式。
2、练习修改、编译和安装新操作系统(1)修改/usr/src/kernel/main.c中的announce函数cd /usr/src/kernelcp main.c main.c.backupvi main.c找到announce函数增加打印语句kprintf(“在这儿增加你想打印的语句”);保存退出vi编辑器(通过键盘左上角ESC键进入命令模式,然后shift+冒号,再键入wq)(2)编译新操作系统cd /usr/src/toolsmake image(3)安装新操作系统make install(4)用新操作系统更换旧操作系统:shutdown在boot monitor下(出现d0p0s0>时),键入boot c0d0p0重新进入新操作系统。
三、实验内容、过程与分析(一)实验内容1、学习《Operating Systems Design and Implementation》(Andrew S. Tanenbaum著,第三版)中的第4章4.8.8小节,Memory Management Utilities,内存管理。
Minix内存管理采用了动态分区分配以及首次适应算法。
第1篇一、实验目的1. 理解操作系统内存分配的基本原理和常用算法。
2. 掌握动态分区分配方式中的数据结构和分配算法。
3. 通过编写程序,实现内存分配和回收功能。
二、实验环境1. 操作系统:Linux2. 编程语言:C语言3. 开发工具:GCC编译器三、实验原理1. 内存分配的基本原理操作系统内存分配是指操作系统根据程序运行需要,将物理内存分配给程序使用的过程。
内存分配算法主要包括以下几种:(1)首次适应算法(First Fit):从内存空间首部开始查找,找到第一个满足条件的空闲区域进行分配。
(2)最佳适应算法(Best Fit):在所有满足条件的空闲区域中,选择最小的空闲区域进行分配。
(3)最坏适应算法(Worst Fit):在所有满足条件的空闲区域中,选择最大的空闲区域进行分配。
2. 动态分区分配方式动态分区分配方式是指操作系统在程序运行过程中,根据需要动态地分配和回收内存空间。
动态分区分配方式包括以下几种:(1)固定分区分配:将内存划分为若干个固定大小的分区,程序运行时按需分配分区。
(2)可变分区分配:根据程序大小动态分配分区,分区大小可变。
(3)分页分配:将内存划分为若干个固定大小的页,程序运行时按需分配页。
四、实验内容1. 实现首次适应算法(1)创建空闲分区链表,记录空闲分区信息,包括分区起始地址、分区大小等。
(2)编写分配函数,实现首次适应算法,根据程序大小查找空闲分区,分配内存。
(3)编写回收函数,回收程序所占用的内存空间,更新空闲分区链表。
2. 实现最佳适应算法(1)创建空闲分区链表,记录空闲分区信息。
(2)编写分配函数,实现最佳适应算法,根据程序大小查找最佳空闲分区,分配内存。
(3)编写回收函数,回收程序所占用的内存空间,更新空闲分区链表。
3. 实验结果分析(1)通过实验,验证首次适应算法和最佳适应算法的正确性。
(2)对比两种算法在内存分配效率、外部碎片等方面的差异。
五、实验步骤1. 创建一个动态内存分配模拟程序,包括空闲分区链表、分配函数和回收函数。
操作系统课程实验年级2012 级专业计算机科学与技术(应用型)姓名学号指导教师日期实验四、存储管理实验一、关键问题1、实验目的理解内存分配和回收原理。
2、实验环境Ubuntu 8.0或者以上,Eclipse集成开发环境3、实验内容3.1 在控制台内观察Linux内存分配情况3.2存储管理模拟实验要求:写一动态分区管理程序,使其内存分配采用最佳适应分配算法。
老师所给的例子为内存分配算法是最先适应分配算法的系统模拟动态分区管理方案,而问题的关键就是如何把最先适应分配算法改为最佳适应分配算法。
二、设计修改思路struct freearea* min1=NULL;//定义了一个符合条件的最小空白块链表首先我们在分配内存函数中需要定义一个记录符合条件的最小空白块的链表结构指针,对当前空闲分区链进行遍历,找到符合条件的最小空白块并记录。
系统为作业分配内存时,根据指针freep查找空闲分区链。
当找到一块可以满足请求中最小的空闲分区时便分配。
当空间被分配后剩余的空间大于规定的碎片,则形成一个较小的空闲分区留在空闲链中。
三、实现修改的关键代码//有两个链:空白块链及作业链.空白块链描述空白块,链首指针freep,初始为一大块空白块.//作业链按从高址到低址的顺序链接,链首指针jobp//为作业jn分配jl大小内存,起始地址为javoid ffallocation(int jl,char jn[10],int* ja){struct mat* jp=NULL;//作业链当前节点struct mat* jp2=NULL;//新的作业节点struct mat* jp1=NULL;//struct freearea* fp=NULL;//当前空白块struct freearea* min1=NULL;//定义了一个符合条件的最小空白块链表int flag=0;int i;*ja=-1;if (totalfree<jl) //剩余空间大小不能满足作业要求return;fp=freep;while (fp!=NULL){if (fp->freesize>jl){ min1=fp;flag=1;break;}fp=fp->next;}if(freep->next!=NULL&&flag==0) {*ja=0;return;}fp=min1->next;while (fp!=NULL){if (fp->freesize>jl&&fp->freesize<min1->freesize)min1=fp;fp=fp->next;//当前空白块大小不满足要求}jobnumber++;totalfree=totalfree-jl;jp2=calloc(1,sizeof(struct mat));//在节点上登记为该作业分配的内存空间// for (i=0;i<10;i++) (jp2->jobname)[i]=' ';i=-1;while(jn[++i])(jp2->jobname)[i]=jn[i];(jp2->jobname)[i]='\0';jp2->joblength=jl;jp2->jobaddress=min1->freeaddress;//登记该作业的起始地址(块的最低地址)*ja=jp2->jobaddress;//将节点jp2插入作业链jobp,按高址到低址的顺序。
操作系统存储管理实验报告一、实验目的操作系统的存储管理是计算机系统中非常重要的组成部分,它直接影响着系统的性能和资源利用率。
本次实验的目的在于深入理解操作系统中存储管理的基本原理和方法,通过实际操作和观察,掌握存储分配、回收、地址转换等关键技术,并对不同存储管理策略的性能进行分析和比较。
二、实验环境本次实验在 Windows 10 操作系统下进行,使用 Visual Studio 2019 作为编程环境,编程语言为 C++。
三、实验内容(一)固定分区存储管理1、原理固定分区存储管理将内存空间划分为若干个固定大小的分区,每个分区只能装入一道作业。
分区的大小可以相等,也可以不等。
2、实现创建一个固定大小的内存空间数组,模拟内存分区。
为每个分区设置状态标志(已分配或空闲),并实现作业的分配和回收算法。
3、实验结果与分析通过输入不同大小的作业请求,观察内存的分配和回收情况。
分析固定分区存储管理的优缺点,如内存利用率低、存在内部碎片等。
(二)可变分区存储管理1、原理可变分区存储管理根据作业的实际需求动态地划分内存空间,分区的大小和数量是可变的。
2、实现使用链表或数组来管理内存空间,记录每个分区的起始地址、大小和状态。
实现首次适应、最佳适应和最坏适应等分配算法,以及分区的合并和回收算法。
3、实验结果与分析比较不同分配算法的性能,如分配时间、内存利用率等。
观察内存碎片的产生和处理情况,分析可变分区存储管理的优缺点。
(三)页式存储管理1、原理页式存储管理将内存空间和作业都划分为固定大小的页,通过页表将逻辑地址转换为物理地址。
2、实现设计页表结构,实现逻辑地址到物理地址的转换算法。
模拟页面的调入和调出过程,处理缺页中断。
3、实验结果与分析测量页式存储管理的页面置换算法(如先进先出、最近最少使用等)的命中率,分析其对系统性能的影响。
探讨页大小的选择对存储管理的影响。
(四)段式存储管理1、原理段式存储管理将作业按照逻辑结构划分为若干个段,每个段有自己的名字和长度。
操作系统实验内存的分配与回收实验报告一、实验题目:内存的分配与回收二、实验内容:利用可变分区的首次适应算法,模拟内存的分配与回收。
三、实验目的:掌握可变分区首次适应算法的原理以及其编程实现。
四、实验过程:1、基本思想:可变分区分配是根据进程的实际需求,动态地为之分配内存空间。
首次适应算法要求空闲空间链以地址递增的次序链接。
进行内存分配时,从链表头部开始依次检索,找到第一个不小于请求空间大小的空闲空间进行分配。
分配时需考虑碎片问题,若分配会导致碎片产生则将整块分区分配。
内存的回收需要考虑四种情况:⑴回收分区前后两个分区都空闲,则需要和前后两个分区合并;(2)回收分区只有前一分区空闲,则与前一分区合并;(3)回收分区只有后一分区空闲,则和后一分区合并;(4)回收分区独立,不考虑合并。
2、主要数据结构:struct FreeArea{ 链结点包含的数据:分区号、大小、起址、标记int ID;int size;long address;int sign;};struct Node { 双链表结点结构体:数据区、前向指针、后继指针FreeArea data;struct Node *prior;struct Node *next;}*DLinkList;3、输入、输出:输入: I.内存分配时由键盘输入分区ID和大小;II.内存回收时由键盘输入需要回收的分区ID;输出:输出内存的分配情况(按照地址从低到高)4、程序流程图:5、实验结果截屏:6、源程序代码:#include<iostream>using namespace std;#define Free 0 //空闲状态#define Busy 1 //已用状态#define PBusy 2 //碎片已用状态#define FINISH 1 //完成#define FINISH2 1 //完成#define ERROR 0 //出错#define memory 512 //最大内存空间为(单位:KB)#define min 10 //碎片最小值(单位:KB)typedef struct FreeArea//空闲链数据{int ID;int size;long address;int sign;};typedef struct Node//空闲连结构{FreeArea data;struct Node *prior;struct Node *next;}*DLinkList;DLinkList head; //头结点DLinkList tail; //尾结点int Create()//初始化{head=(DLinkList)malloc(sizeof(Node));//分配内存tail=(DLinkList)malloc(sizeof(Node));head->prior=NULL;head->next=tail;tail->prior=head;tail->next=NULL;tail->data.address=0;tail->data.size=memory;tail->data.ID=0;tail->data.sign=Free;return FINISH;}int FirstFit(int ID,int request)//首次适应算法{DLinkList temp=(DLinkList)malloc(sizeof(Node));//新建作业的结点temp->data.ID=ID;temp->data.size=request;temp->data.sign=Busy;Node *p=head;//插入指针Pwhile(p){if(p->data.sign==Free && p->data.size==request)//剩余大小恰好满足{p->data.sign=Busy;p->data.ID=ID;return FINISH;break;}else if(p->data.sign==Free&& p->data.size>request&& (p->data.size-request>min))//满足需求且有剩余且不产生碎片{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=p->data.size-request;return FINISH;break;}else if(p->data.sign==Free&& p->data.size>request&& p->data.size-request<=min)//产生碎片时{p->data.sign=PBusy;p->data.ID=ID;return FINISH;break;}p=p->next;//若前面的分区都已分配,P指针后移}return ERROR;}int Allocate()//主存分配{int ID,request;cout<<"请输入作业所在分区号:";cin>>ID;cout<<"请输入分配的主存(单位:KB):";cin>>request;if(request<0 ||request==0){cout<<"分配的主存必须是正整数!"<<endl;return ERROR;}if(FirstFit(ID,request)==FINISH)cout<<"分配成功!"<<endl;elsecout<<"内存不足,分配失败!"<<endl;}int Recycle(int ID)//回收{Node *p=head;while(p){if(p->data.ID==ID){p->data.sign=Free;//p->data.ID=Free;if((p->prior->data.sign==Free)&&(p->next->data.sign==Free))//与前后的空闲块相连{p->prior->data.size=p->prior->data.size+p->data.size+p->next->data.size;p->prior->next=p->next->next;if(p->next->next==NULL)//若p->next是最后一个结点{p->prior->data.ID=Free;p->next=NULL;}else{p->next->next->prior=p->prior;}break;}if(p->prior->data.sign==Free)//与前面的空闲块相连{p->prior->data.size+=p->data.size;p->prior->next=p->next;p->next->prior=p->prior;break;}if(p->next->data.sign==Free)//与后面的空闲块相连{p->data.size+=p->next->data.size;if(p->next->next==NULL)//若p->next是最后一个结点p->next=NULL;else{p->next->next->prior=p;p->next=p->next->next;}break;}break;}p=p->next;}cout<<"分区:"<<ID<<"回收成功"<<endl;return FINISH;}void show()//显示{cout<<" 主存分配情况\n";Node *p=head->next;while(p){cout<<"分区号:";if(p->data.ID==Free)cout<<"Free"<<endl;elsecout<<p->data.ID<<endl;cout<<"起始地址:"<<p->data.address;cout<<" 分区大小:"<<p->data.size<<" KB";cout<<" 状态:";if(p->data.sign==Free)cout<<"空闲"<<endl;else if(p->data.sign==PBusy)cout<<"碎片已分配"<<endl;elsecout<<"已分配"<<endl;p=p->next;}cout<<endl;}void main(){Create();int choice;int i;for(i=0;;i++){cout<<"请输入操作:";cout<<"1.分配内存 2.回收内存 3.显示主存0.退出";cout<<endl;cin>>choice;if(choice==1)// 分配内存Allocate();else if(choice==2)// 内存回收{ i nt ID;cout<<"请输入要释放的分区号:";cin>>ID;Recycle(ID);}else if(choice==3)//显示主存show();else if(choice==0)//退出break;else//非法输入{cout<<"输入有误!"<<endl;continue;}}}。
内存连续分配方式实验内存连续分配是操作系统中的重要概念之一、在计算机系统中,内存分配是指将进程所需的内存空间分配给其使用,同时也需要满足内存管理的要求。
内存连续分配方式是指将进程所需的内存空间连续地划分并分配给进程。
下面将介绍内存连续分配的几种方式及实验。
1.固定分区分配方式:固定分区分配方式是将整个内存空间分为若干个大小相等的分区,并为每个分区分配一个进程。
这种分配方式适用于进程数固定或进程大小相对稳定的场景。
固定分区分配方式的优点是简单易实现,缺点是可能会造成内存空间浪费,同时,当进程数或进程大小发生变化时,需要重新划分分区,性能较差。
2.动态分区分配方式:动态分区分配方式是根据进程的实际需要动态地分配内存空间。
动态分区分配方式将内存空间划分为若干个大小不等的分区,每个分区都可以独立地分配给进程使用。
当有新进程需要内存空间时,系统会根据分区空闲情况找到合适的分区进行分配。
动态分区分配方式的优点是充分利用内存空间,缺点是可能会出现内存碎片问题。
3.伙伴系统分配方式:伙伴系统分配方式是一种动态分区分配方式的改进版本。
它将内存空间划分为若干个大小相等的块,每个块大小都是2的幂。
当有新进程需要内存空间时,系统会找到与其大小最接近的空闲块进行分配。
如果找到的块大于所需大小,则将其划分为两个大小相等的块,其中一个分配给进程,另一个留作备用;如果找到的块小于所需大小,则会继续查找更大的空闲块进行分配。
伙伴系统分配方式的优点是减少了内存碎片问题,缺点是实现较为复杂。
实验设计:1.实验目的:通过实验,测试和比较不同的内存连续分配方式在不同场景下的性能和效果。
2.实验环境:使用一台具备内存管理功能的计算机,并在上面运行操作系统。
3.实验步骤:a.首先,选择一种内存连续分配方式,如固定分区分配方式。
b.根据选择的分配方式,设置相应的分区大小和数量。
c.运行一些需要内存空间的进程,并观察它们的分配情况。
d.记录每个进程所分配到的内存空间大小和位置,以及未分配的内存空间大小和位置。
操作系统实验-内存管理操作系统实验内存管理在计算机系统中,内存管理是操作系统的核心任务之一。
它负责有效地分配和管理计算机内存资源,以满足各种程序和进程的需求。
通过本次操作系统实验,我们对内存管理有了更深入的理解和认识。
内存是计算机用于存储正在运行的程序和数据的地方。
如果没有有效的内存管理机制,计算机系统将无法高效地运行多个程序,甚至可能会出现内存泄漏、内存不足等严重问题。
在实验中,我们首先接触到的是内存分配策略。
常见的内存分配策略包括连续分配和离散分配。
连续分配是将内存空间视为一个连续的地址空间,程序和数据被依次分配到连续的内存区域。
这种方式简单直观,但容易产生内存碎片,降低内存利用率。
离散分配则将内存分成大小相等或不等的块,根据需求进行分配。
其中分页存储管理和分段存储管理是两种常见的离散分配方式。
分页存储管理将内存空间划分为固定大小的页,程序也被分成相同大小的页,通过页表进行映射。
分段存储管理则根据程序的逻辑结构将其分成不同的段,如代码段、数据段等,每个段有不同的访问权限和长度。
接下来,我们研究了内存回收算法。
当程序不再使用分配的内存时,操作系统需要回收这些内存以便再次分配。
常见的内存回收算法有首次适应算法、最佳适应算法和最坏适应算法。
首次适应算法从内存的起始位置开始查找,找到第一个满足需求的空闲区域进行分配;最佳适应算法则选择大小最接近需求的空闲区域进行分配;最坏适应算法选择最大的空闲区域进行分配。
为了更直观地理解内存管理的过程,我们通过编程实现了一些简单的内存管理算法。
在编程过程中,我们深刻体会到了数据结构和算法的重要性。
例如,使用链表或二叉树等数据结构来表示空闲内存区域,可以提高内存分配和回收的效率。
在实验中,我们还遇到了一些实际的问题和挑战。
比如,如何处理内存碎片的问题。
内存碎片是指内存中存在一些无法被有效利用的小空闲区域。
为了解决这个问题,我们采用了内存紧缩技术,将分散的空闲区域合并成较大的连续区域。
西安邮电大学(计算机学院)课内实验报告实验名称:内存管理专业名称:软件工程班级:学生姓名:学号(8位):指导教师:实验日期:实验五:进程1.实验目的通过深入理解区管理的三种算法,定义相应的数据结构,编写具体代码。
充分模拟三种算法的实现过程,并通过对比,分析三种算法的优劣。
(1)掌握内存分配FF,BF,WF策略及实现的思路;(2)掌握内存回收过程及实现思路;(3)参考给出的代码思路,实现内存的申请、释放的管理程序,调试运行,总结程序设计中出现的问题并找出原因,写出实验报告。
2.实验要求:1)掌握内存分配FF,BF,WF策略及实现的思路;2)掌握内存回收过程及实现思路;3)参考本程序思路,实现内存的申请、释放的管理程序,调试运行,总结程序设计中出现的问题并找出原因,写出实验报告。
3.实验过程:创建进程:删除其中几个进程:(默认以ff首次适应算法方式排列)Bf最佳适应算法排列方式:wf最差匹配算法排列方式:4.实验心得:这次实验实验时间比较长,而且实验指导书中对内存的管理讲的很详细,老师上课的时候也有讲的很详细,但是代码比较长,刚开始的时候也是不太懂,但是后面经过和同学一起商讨,明白几种算法的含义:①首次适应算法。
在采用空闲分区链作为数据结构时,该算法要求空闲分区链表以地址递增的次序链接。
在进行内存分配时,从链首开始顺序查找,直至找到一个能满足进程大小要求的空闲分区为止。
然后,再按照进程请求内存的大小,从该分区中划出一块内存空间分配给请求进程,余下的空闲分区仍留在空闲链中。
②循环首次适应算法。
该算法是由首次适应算法演变而形成的,在为进程分配内存空间时,从上次找到的空闲分区的下一个空闲分区开始查找,直至找到第一个能满足要求的空闲分区,并从中划出一块与请求的大小相等的内存空间分配给进程。
③最佳适应算法将空闲分区链表按分区大小由小到大排序,在链表中查找第一个满足要求的分区。
④最差匹配算法将空闲分区链表按分区大小由大到小排序,在链表中找到第一个满足要求的空闲分区。
操作系统实验之内存管理实验报告一、实验目的内存管理是操作系统的核心功能之一,本次实验的主要目的是深入理解操作系统中内存管理的基本原理和机制,通过实际编程和模拟操作,掌握内存分配、回收、地址转换等关键技术,提高对操作系统内存管理的认识和实践能力。
二、实验环境本次实验在 Windows 操作系统下进行,使用 Visual Studio 作为编程环境,编程语言为 C++。
三、实验原理1、内存分配算法常见的内存分配算法有首次适应算法、最佳适应算法和最坏适应算法等。
首次适应算法从内存的起始位置开始查找,找到第一个满足需求的空闲分区进行分配;最佳适应算法则选择大小最接近需求的空闲分区;最坏适应算法选择最大的空闲分区进行分配。
2、内存回收算法当进程结束释放内存时,需要将其占用的内存区域回收至空闲分区链表。
回收过程中需要考虑相邻空闲分区的合并,以减少内存碎片。
3、地址转换在虚拟内存环境下,需要通过页表将逻辑地址转换为物理地址,以实现进程对内存的正确访问。
四、实验内容1、实现简单的内存分配和回收功能设计一个内存管理模块,能够根据指定的分配算法为进程分配内存,并在进程结束时回收内存。
通过模拟多个进程的内存请求和释放,观察内存的使用情况和变化。
2、实现地址转换功能构建一个简单的页式存储管理模型,模拟页表的建立和地址转换过程。
给定逻辑地址,能够正确计算出对应的物理地址。
五、实验步骤1、内存分配和回收功能实现定义内存分区的数据结构,包括起始地址、大小、使用状态等信息。
实现首次适应算法、最佳适应算法和最坏适应算法的函数。
创建空闲分区链表,初始化为整个内存空间。
模拟进程的内存请求,调用相应的分配算法进行内存分配,并更新空闲分区链表。
模拟进程结束,回收内存,处理相邻空闲分区的合并。
2、地址转换功能实现定义页表的数据结构,包括页号、页框号等信息。
给定页面大小和逻辑地址,计算页号和页内偏移。
通过页表查找页框号,结合页内偏移计算出物理地址。
组号成绩计算机操作系统课程设计报告题目内存的连续分配算法专业:计算机科学与技术班级:学号姓名:指导教师:2016年12月 26 日一、设计目的掌握内存的里联系分配方式的各种算法。
二、设计内容本系统模拟操作系统内存分配算法的实现,实现可重定位分区分配算法,采用PCB定义结构体来表示一个进程,定义了进程的名称和大小,进程内存起始地址和进程状态。
内存分区表用空闲分区表的形式来模拟实现。
三、设计原理动态分区的实现是根据进程所申请的内存大小来决定动态的由系统进行分配内存空间大小,因此分区表里的空闲分区个数是不定的,根据进程数和进程大小决定的。
可重定位分区算法比动态分区算法增加了紧凑的功能。
四、详细设计及编码1、模块分析该实验可分为三大部分,每一部分又由个数不同的几个函数实现。
第一部分是装入作业,第二部分是内存回收,第三部分是进行紧凑。
装入作业的时候首先初始化一个链表,根据用户输入的操作代号进行相应的操作。
若用户选择装入作业首先判断空闲分区表里有没有比作业需要的内存大的分区,若有直接分配,若没有进行紧凑操作,再将紧凑后的空闲分区与作业大小比较,若能装的下则分配给作业,若是进行紧凑后的空闲分区仍不能装入整个作业则通知用户内存不够。
2、流程图2、代码实现#include<stdio.h>#include<stdlib.h>#include<time.h>#include<windows.h>#define TURE 1#define FALSE 0#define OK 1#define ERROR 0#define INFEASIBLE -1#define OVERFLOW -2#define SIZE 3//进程表int ppNo=1; //用于递增生成进程号int pLength=0;struct PCB{int pNo; //进程号(名)int pSize; // 进程大小int pOccupy; // 实际占用的内存int pStartAddr; // 进程起始地址int pState; //进程状态};struct PCB pList[200];//////////////////空闲分区表部分/////////////////////////////////////////////////////typedef int Status;typedef struct emptyNode{ //空闲分区结构体int areaSize; //空闲分区大小int aStartAddr; //空闲分区始址struct emptyNode *next;}emptyNode,*LinkList;int ListDelete(struct PCB *pList,int i);//删除下标为i的进程void pSort(struct PCB *pList); //内存中的进程按始址递增排序void compact(LinkList &L,struct PCB *pList);//紧凑,内存中进程移动,修改进程数据结构;空闲分区合并,修改空闲分区表数据结构void amalgamate(LinkList &L); //回收后进行合并空闲分区void recycle(LinkList &L,struct PCB *pList); //回收,从进程表中删除进程,把释放出的空间插入到空闲分区链表中Status InitList(LinkList &L); ///构造一个新的有头节点的空链表L Status ClearList(LinkList &L); ///将链表L重置为空表Status ListInsert(LinkList &L,LinkList s1); //根据始址进行插入void DeleteElem(LinkList &L,int aStartAddr);//删除线性表中始址值为aStartAddr的结点void PrintList(LinkList L); //输出各结点的值void creatP(struct PCB *p); ///初始化进程int search(LinkList &L,int pSize); //检索分区表,返回合适分区的首址int add(LinkList &L); //返回空闲分区总和void pListPrint(struct PCB *pList); //AAA/输出内存中空间占用情况void distribute(LinkList &L,struct PCB *process);int ListDelete(struct PCB *pList,int i)//AAA/删除下标为i的进程{for(;i<pLength-1;i++){pList[i]=pList[i+1];}pLength--;}//ListDeletevoid pSort(struct PCB *pList){ //AAA/内存中的进程按始址递增排序int i,j;struct PCB temp;for(i=0;i<pLength-1;i++){for(j=0;j<pLength-i-1;j++){if(pList[j].pStartAddr>pList[j+1].pStartAddr){temp=pList[j];pList[j]=pList[j+1];pList[j+1]=temp;}}}}void compact(LinkList &L,struct PCB *pList){//AAA/紧凑,内存中进程移动,修改进程数据结构;空闲分区合并,修改空闲分区表数据结构printf("进行紧凑\n");//1、进程移动,修改进程数据结构int i;pList[0].pStartAddr=0; //第一个进程移到最上面for(i=0;i<pLength-1;i++){pList[i+1].pStartAddr=pList[i].pStartAddr+pList[i].pOccupy;}//2、空闲分区合并,修改空闲分区表数据结构LinkList p=L->next,s;int sumEmpty=0;while(p!=NULL)//求空闲区总和{sumEmpty+=p->areaSize;p=p->next;}//printf("清空前\n");//PrintList(L);ClearList(L); //清空空闲分区表//printf("清空后\n");//PrintList(L);s=(LinkList)malloc(sizeof(emptyNode));s->aStartAddr=pList[pLength-1].pStartAddr+pList[pLength-1].pOccupy;s->areaSize=sumEmpty;ListInsert(L,s);//printf("插入后\n");//PrintList(L);// p rintf("\n紧凑后的>>>>\n");pListPrint(pList);PrintList(L);}void amalgamate(LinkList &L){//AAA/回收后进行合并空闲分区LinkList p=L->next,q=p->next;while(q!=NULL){if(p->aStartAddr+p->areaSize==q->aStartAddr){p->areaSize+=q->areaSize;DeleteElem(L,q->aStartAddr);//删除被合并的结点q=p->next;}else{p=q;q=q->next;}}}void recycle(LinkList &L,struct PCB *pList){//AAA/回收,从进程表中删除进程,把释放出的空间插入到空闲分区链表中int index,delPNo,delPSize,delPOccupy,delPStartAddr;LinkList s;//srand(time(0));//index=rand()%pLength;printf("请输入要回收的进程号:");scanf("%d",&index);delPNo=pList[index-1].pNo;delPSize=pList[index-1].pSize;delPOccupy=pList[index-1].pOccupy;delPStartAddr=pList[index-1].pStartAddr;//printf("__________________________________________________________________ ______________");ListDelete(pList,index-1);//pListPrint(pList);s=(LinkList)malloc(sizeof(emptyNode));s->areaSize=delPOccupy;s->aStartAddr=delPStartAddr;ListInsert(L,s);amalgamate(L);pListPrint(pList);//输出内存中空间占用情况PrintList(L);/////////////////////////////////////////////////////////////////////////////Status InitList(LinkList &L) //1AAA/构造一个新的有头节点的空链表L {LinkList s;L=(LinkList)malloc(sizeof(emptyNode)); //生成新节点(头结点)if(!L) return ERROR; //申请内存失败s=(LinkList)malloc(sizeof(emptyNode));s->areaSize=100;s->aStartAddr=0;L->next=s; //头节点的指针域指向第一个结点s->next=NULL;return OK;}//InitListStatus ClearList(LinkList &L) //2AAA/将链表L重置为空表{LinkList p,r;p=L->next; r=p->next;while(p!=NULL){free(p);if(r==NULL){p=NULL;}else{p=r;r=p->next;}}L->next=NULL;return OK;}//ClearListStatus ListInsert(LinkList &L,LinkList s1) //AAA/*****根据始址进行插入{LinkList r=L,p=L->next,s;//指针s=(LinkList)malloc(sizeof(emptyNode));s->areaSize=s1->areaSize;s->aStartAddr=s1->aStartAddr;if(p==NULL){L->next=s;s->next=NULL;}else{while(p!=NULL){if(s1->aStartAddr < p->aStartAddr){s->next=r->next;r->next=s;break;}r=p;p=p->next; //后移}if(p==NULL){r->next=s;s->next=NULL;}}return OK;}//ListInsert2void DeleteElem(LinkList &L,int aStartAddr)//*****删除线性表中始址值为aStartAddr 的结点{LinkList p=L,q;while(p->next!=NULL){q=p->next;if(q->aStartAddr==aStartAddr){p->next=q->next;free(q);}elsep=p->next;}}//DeleteElem///////////////////////////////////////////////////////////////////////////////void PrintList(LinkList L)//AAA/*****输出各结点的值{LinkList p=L->next;while(p!=NULL){printf(" %d \t\t\t%d KB\n",p->aStartAddr,p->areaSize);p=p->next;}printf("\n");}//PrintListvoid creatP(struct PCB *p){ //AAA/初始化进程int size;//srand(time(NULL));//size=rand()%7+1;printf("请输入进程大小:");scanf("%d",&size);//size=10;p->pNo=ppNo++;p->pSize=size;p->pOccupy=0;p->pStartAddr=0;p->pState=0;}int search(LinkList &L,int pSize){ //AAA/检索分区表,返回合适分区的首址LinkList p=L->next;while(p!=NULL){if(p->areaSize>=pSize){////成功printf("search分区%d %d\n",p->areaSize,pSize);return p->aStartAddr;}p=p->next;}return -1;//没有足够大的}int add(LinkList &L){ //AAA/返回空闲分区总和LinkList p=L->next;int sum=0;while(p!=NULL){sum+=p->areaSize;p=p->next;}return sum;}void pListPrint(struct PCB *pList){//AAA/输出内存中空间占用情况printf("\n进程分配情况: 起始地址\t\t大小\t\t进程号\n");for(int i=0;i<pLength;i++){printf(" %d\t\t\t %d K\t\t%d\n",pList[i].pStartAddr,pList[i].pOccupy,pList[i].pNo);}}void distribute(LinkList &L,struct PCB *process){LinkList p=L->next;while(p!=NULL){if(p->areaSize>=process->pSize)break;p=p->next;}//printf("%d KB < %d KB",process->pSize,p->areaSize);////////////////////if(p->areaSize-process->pSize<=SIZE){//不用分割全部分配(直接删除此空闲分区结点)process->pStartAddr=p->aStartAddr; //进程始址变化process->pState=1; //进程状态process->pOccupy=p->areaSize; //进程实际占用内存为改空闲分区的大小pList[pLength++]= *process; //把进程加入进程列表pSort(pList);pListPrint(pList);//输出内存中空间占用情况DeleteElem(L,p->aStartAddr);}else{//分割分配process->pStartAddr=p->aStartAddr; //进程始址变化process->pState=1; //进程状态process->pOccupy=process->pSize; //进程实际占用内存为该进程的大小pList[pLength++]= *process; //把进程加入进程列表pSort(pList); //进程排序pListPrint(pList);//输出内存中空间占用情况p->aStartAddr+=process->pSize; //空闲分区始址变化p->areaSize-=process->pOccupy; //空闲分区大小变化}}///////////////////////////////////////////////////////int main(){struct PCB p;int i,num,dele,k,stAddr,flag;LinkList s,L;if(!InitList(L)) //初始化空闲分区表printf("创建表失败\n");while(1){printf("请选择要进行的操作(1:装入;2:回收)");int flag;scanf("%d",&flag);if(flag==1){creatP(&p);//初始化进程//printf("_________________________________________________________________ _______________");printf("待装入作业:%d Size = %d KB\n",p.pNo,p.pSize);//1、请求分配size//2、检索空闲分区表(首次适应FF)//PrintList(L);stAddr=search(L,p.pSize);//得到足够大的分区的始址,没有则返回-1if(stAddr==-1){//没有足够大的分区if(add(L)>=p.pSize){//空闲区总和足够大// printf("没有足够大的空闲分区但空闲总和足够大\n");//紧凑compact(L,pList);//按动态分区方式分配distribute(L,&p);PrintList(L);//compact(L,pList); //紧凑}else{ //空闲区总和不足printf("分配失败\n\n");}}else{//有足够大的distribute(L,&p);PrintList(L);//compact(L,pList); //紧凑}}else{//回收if(pLength>0){recycle(L,pList);//compact(L,pList); //紧凑}else{printf("无可回收内存!");}}//system("pause");// scanf("%d")} //whilereturn 0;}四、结果及其相关分析结果分析:连续进行4次装入的操作后内存中还剩30K的空间,接着进行一次回收内存的操作,回收作业1后不连续的空闲内存共有50K,接着再装入一个35K的作业,分散的两个分区都不能装入作业,但是总和可以装入,所以先进行紧凑再分配,重新分配后还剩15K的内存。
实验链表实验报告一、实验目的本次实验的主要目的是深入理解链表这种数据结构的概念、特点和操作方法,并通过实际编程实现来提高对链表的应用能力。
二、实验环境本次实验使用的编程语言为C++,开发工具为Visual Studio 2019。
三、实验原理链表是一种常见的数据结构,它由一系列节点组成,每个节点包含数据和指向下一个节点的指针。
与数组不同,链表的内存分配是动态的,并且可以方便地进行插入和删除操作,而不需要移动大量的元素。
链表分为单向链表、双向链表和循环链表等多种类型。
在本次实验中,我们主要实现单向链表。
单向链表的节点结构通常包含数据域和指针域。
数据域用于存储节点的数据,指针域用于指向下一个节点。
通过遍历链表的指针,可以访问链表中的每个节点。
四、实验内容1、链表节点的定义```cppstruct ListNode {int data;ListNode next;ListNode(int x) : data(x), next(NULL) {}};```2、链表的创建```cppListNode createList(){ListNode head = NULL;ListNode tail = NULL;int num;cout <<"请输入链表中的数字(输入-1 结束):";cin >> num;while (num!=-1) {ListNode newNode = new ListNode(num);if (head == NULL) {head = newNode;tail = newNode;} else {tail>next = newNode;tail = newNode;}cin >> num;}return head;}```3、链表的遍历```cppvoid traverseList(ListNode head) {ListNode curr = head;while (curr!= NULL) {cout << curr>data <<"";curr = curr>next;}cout << endl;}```4、链表的插入```cppvoid insertNode(ListNode& head, int position, int value) {ListNode newNode = new ListNode(value);if (position == 0) {newNode>next = head;head = newNode;return;}ListNode curr = head;int count = 0;while (curr!= NULL && count < position 1) {curr = curr>next;count++;}if (curr == NULL) {cout <<"插入位置超出链表长度" << endl; return;}newNode>next = curr>next;curr>next = newNode;}```5、链表的删除```cppvoid deleteNode(ListNode& head, int position) {if (head == NULL) {cout <<"链表为空,无法删除" << endl; return;}if (position == 0) {ListNode temp = head;head = head>next;delete temp;return;}ListNode curr = head;ListNode prev = NULL;int count = 0;while (curr!= NULL && count < position) {prev = curr;curr = curr>next;count++;}if (curr == NULL) {cout <<"删除位置超出链表长度" << endl; return;}prev>next = curr>next;delete curr;}```五、实验结果通过对上述链表操作函数的调用,我们成功地创建、遍历、插入和删除了链表中的节点。
实验四存储器管理一、实验名称:存储器管理二、实验目的在TC、VB、Delphi、C++Builder等语言与开发环境中,模拟操作系统的内存管理;通过程序运行所显示的内存使用的各项指标,加深对内存管理的理解。
三、实验内容实现主存储器空间的分配和回收。
本实验有两个题,学生可选择其中的一题做实验。
第一题:在固定分区管理方式下实现主存分配和回收。
第二题:在可变分区管理方式下采用最先适应算法实现主存分配和实现主存回收。
[提示]:可变分区方式是按作业需要的主存空间大小来分割分区的。
当要装入一个作业时,根据作业需要的主存量查看是否有足够的空闲空间,若有,则按需要量分割一个分区分配给该作业;若无,则作业不能装入。
随着作业的装入、撤离,主存空间被分成许多个分区,有的分区被作业占用,而有的分区是空闲的。
为了说明哪些区是空闲的,可以用来装入新作业,必须要有一张空闲区说明表,格式如下:起址长度状态第一栏14 K 12 K 未分配第二栏32 K 96 K 未分配空表目空表目其中,起址——指出一个空闲区的主存起始地址。
长度——指出从起始地址开始的一个连续空闲的长度。
状态——有两种状态,一种是“未分配”状态,指出对应的由起址指出的某个长度的区域是空闲区;另一种是“空表目”状态,表示表中对应的登记项目是空白(无效),可用来登记新的空闲区(例如,作业撤离后,它所占的区域就成了空闲区,应找一个“空表目”栏登记归还区的起址和长度且修改状态)。
由于分区的个数不定,所以空闲区说明表中应有适量的状态为“空表目”的登记栏目,否则造成表格“溢出”无法登记。
空闲区表的定义为:#define m 10 /*假定系统允许的空闲区表最大为m*/struct{ float address; /*起始地址*/float length; /*长度*/int flag; /*标志,用“0”表示空栏目,用“1”表示未分配*/ }free_table[m]; /*空闲区表*/上述的这张说明表的登记情况是按提示(1)中的例所装入的三个作业占用的主存区域后填写的。
#include<stdio.h>#include<stdlib.h>#define OK 1 //完成#define ERROR 0 //出错typedef int Status;typedef struct free_table//定义一个空闲区说明表结构{int num; //分区序号long address; //起始地址long length; //分区大小int state; //分区状态}ElemType;typedef struct Node// 线性表的双向链表存储结构{ElemType data;struct Node *prior; //前趋指针struct Node *next; //后继指针}Node,*LinkList;LinkList first; //头结点LinkList end; //尾结点int flag;//记录要删除的分区序号Status Initblock()//开创带头结点的内存空间链表{first=(LinkList)malloc(sizeof(Node));end=(LinkList)malloc(sizeof(Node));first->prior=NULL;first->next=end;end->prior=first;end->next=NULL;end->data.num=1;end->data.address=40;end->data.length=600;end->data.state=0;return OK;}void sort()//分区序号重新排序{Node *p=first->next,*q;q=p->next;for(;p!=NULL;p=p->next){for(q=p->next;q;q=q->next){if(p->data.num>=q->data.num){q->data.num+=1;}}}}//显示主存分配情况void show(){ int flag=0;//用来记录分区序号Node *p=first;p->data.num=0;p->data.address=0;p->data.length=40;p->data.state=1;sort();printf("\n\t\t》主存空间分配情况《\n");printf("**********************************************************\n\n");printf("分区序号\t起始地址\t分区大小\t分区状态\n\n");while(p){printf("%d\t\t%d\t\t%d",p->data.num,p->data.address,p->data.length);if(p->data.state==0) printf("\t\t空闲\n\n");else printf("\t\t已分配\n\n");p=p->next;}printf("**********************************************************\n\n");}//首次适应算法Status First_fit(int request){//为申请作业开辟新空间且初始化Node *p=first->next;LinkList temp=(LinkList)malloc(sizeof(Node));temp->data.length=request;temp->data.state=1;p->data.num=1;while(p){if((p->data.state==0)&&(p->data.length==request)){//有大小恰好合适的空闲块p->data.state=1;return OK;break;}else if((p->data.state==0) && (p->data.length>request)){//有空闲块能满足需求且有剩余temp->prior=p->prior;temp->next=p;temp->data.address=p->data.address;temp->data.num=p->data.num;p->prior->next=temp;p->prior=temp;p->data.address=temp->data.address+temp->data.length;p->data.length-=request;p->data.num+=1;return OK;break;}p=p->next;}return ERROR;}//最佳适应算法Status Best_fit(int request){int ch; //记录最小剩余空间Node *p=first;Node *q=NULL; //记录最佳插入位置LinkList temp=(LinkList)malloc(sizeof(Node));temp->data.length=request;temp->data.state=1;p->data.num=1;while(p) //初始化最小空间和最佳位置{if((p->data.state==0) && (p->data.length>=request) ) {if(q==NULL){q=p;ch=p->data.length-request;}else if(q->data.length > p->data.length){q=p;ch=p->data.length-request;}}p=p->next;}if(q==NULL) return ERROR;//没有找到空闲块else if(q->data.length==request){q->data.state=1;return OK;}else{temp->prior=q->prior;temp->next=q;temp->data.address=q->data.address;temp->data.num=q->data.num;q->prior->next=temp;q->prior=temp;q->data.address+=request;q->data.length=ch;q->data.num+=1;return OK;}return OK;}//最差适应算法Status Worst_fit(int request){int ch; //记录最大剩余空间Node *p=first->next;Node *q=NULL; //记录最佳插入位置LinkList temp=(LinkList)malloc(sizeof(Node));temp->data.length=request;temp->data.state=1;p->data.num=1;while(p) //初始化最大空间和最佳位置{if(p->data.state==0 && (p->data.length>=request) ){if(q==NULL){q=p;ch=p->data.length-request;}else if(q->data.length < p->data.length){q=p;ch=p->data.length-request;}}p=p->next;}if(q==NULL) return ERROR;//没有找到空闲块else if(q->data.length==request){q->data.length=1;return OK;}else{temp->prior=q->prior;temp->next=q;temp->data.address=q->data.address;temp->data.num=q->data.num;q->prior->next=temp;q->prior=temp;q->data.address+=request;q->data.length=ch;q->data.num+=1;return OK;}return OK;}//分配主存Status allocation(int a){int request;//申请内存大小printf("请输入申请分配的主存大小(单位:KB):"); scanf("%d",&request);if(request<0 ||request==0){printf("分配大小不合适,请重试!");return ERROR;}switch(a){case 1: //默认首次适应算法if(First_fit(request)==OK) printf("\t****分配成功!****");else printf("\t****内存不足,分配失败!****");return OK;break;case 2: //选择最佳适应算法if(Best_fit(request)==OK) printf("\t****分配成功!****");else printf("\t****内存不足,分配失败!****");return OK;break;case 3: //选择最差适应算法if(Worst_fit(request)==OK) printf("\t****分配成功!****");else printf("\t****内存不足,分配失败!****");return OK;break;}}Status deal1(Node *p)//处理回收空间{Node *q=first;for(;q!=NULL;q=q->next){if(q==p){if(q->prior->data.state==0&&q->next->data.state!=0){q->prior->data.length+=q->data.length;q->prior->next=q->next;q->next->prior=q->prior;q=q->prior;q->data.state=0;q->data.num=flag-1;}if(q->prior->data.state!=0&&q->next->data.state==0){q->data.length+=q->next->data.length;q->next=q->next->next;q->next->next->prior=q;q->data.state=0;q->data.num=flag;}if(q->prior->data.state==0&&q->next->data.state==0){q->prior->data.length+=q->data.length;q->prior->next=q->next;q->next->prior=q->prior;q=q->prior;q->data.state=0;q->data.num=flag-1;}if(q->prior->data.state!=0&&q->next->data.state!=0){q->data.state=0;}}}return OK;}Status deal2(Node *p)//处理回收空间{Node *q=first;for(;q!=NULL;q=q->next){if(q==p){if(q->prior->data.state==0&&q->next->data.state!=0){q->prior->data.length+=q->data.length;q->prior->next=q->next;q->next->prior=q->prior;q=p->prior;q->data.state=0;q->data.num=flag-1;}if(q->prior->data.state!=0&&q->next->data.state==0){q->data.state=0;}if(q->prior->data.state==0&&q->next->data.state==0){q->prior->data.length+=q->data.length;q->prior->next=q->next;q->next->prior=q->prior;q=q->prior;q->data.state=0;q->data.num=flag-1;}if(q->prior->data.state!=0&&q->next->data.state!=0){q->data.state=0;}}}return OK;}//主存回收Status recovery(int flag){Node *p=first;for(;p!=NULL;p=p->next){if(p->data.num==flag){if(p->prior==first){if(p->next!=end)//当前P指向的下一个不是最后一个时{if(p->next->data.state==0) //与后面的空闲块相连{p->data.length+=p->next->data.length;p->next->next->prior=p;p->next=p->next->next;p->data.state=0;p->data.num=flag;}else p->data.state=0;}if(p->next==end)//当前P指向的下一个是最后一个时{p->data.state=0;}}//结束if(p->prior==block_first)的情况else if(p->prior!=first){if(p->next!=end){deal1(p);}else{deal2(p);}}//结束if(p->prior!=block_first)的情况}//结束if(p->data.num==flag)的情况}printf("\t****回收成功****");return OK;}//主函数void main(){int i; //操作选择标记int a;//算法选择标记printf("**********************************************************\n"); printf("\t\t用以下三种方法实现主存空间的分配\n");printf("\t(1)首次适应算法\t(2)最佳适应算法\t(3)最差适应算法\n"); printf("**********************************************************\n"); printf("\n");printf("请输入所使用的内存分配算法:");scanf("%d",&a);while(a<1||a>3){printf("输入错误,请重新输入所使用的内存分配算法:\n"); scanf("%d",&a);}switch(a){case 1:printf("\n\t****使用首次适应算法:****\n");break;case 2:printf("\n\t****使用最佳适应算法:****\n");break;case 3:printf("\n\t****使用最坏适应算法:****\n");break;}Initblock(); //开创空间表while(1){show();printf("\t1: 分配内存\t2: 回收内存\t0: 退出\n");printf("请输入您的操作:");scanf("%d",&i);if(i==1)allocation(a); // 分配内存else if(i==2) // 内存回收{printf("请输入您要释放的分区号:");scanf("%d",&flag);recovery(flag);}else if(i==0){printf("\n退出程序\n");break; //退出}else //输入操作有误{printf("输入有误,请重试!");continue;}}}八、执行结果和结果分析初始化首次适应算法:当作业1、2、3顺利分配内存空间后:回收序号2里面的内存:分配作业4:回收序号3里面的内存(与上邻序号2相连了)回收序号1里的内存(与下邻序号2相连了)继续分配(会发现总是按顺序查找满足要求的第一个空闲块,一旦发现就会分配):。
操作系统实验报告三一、实验目的本次操作系统实验的目的在于深入了解操作系统的进程管理、内存管理和文件系统等核心功能,通过实际操作和观察,增强对操作系统原理的理解和掌握,提高解决实际问题的能力。
二、实验环境本次实验在 Windows 10 操作系统环境下进行,使用了 Visual Studio 2019 作为编程工具,并借助了相关的操作系统模拟软件和调试工具。
三、实验内容与步骤(一)进程管理实验1、创建多个进程使用 C++语言编写程序,通过调用系统函数创建多个进程。
观察每个进程的运行状态和资源占用情况。
2、进程同步与互斥设计一个生产者消费者问题的程序,使用信号量来实现进程之间的同步与互斥。
分析在不同并发情况下程序的执行结果,理解进程同步的重要性。
(二)内存管理实验1、内存分配与回收实现一个简单的内存分配算法,如首次适应算法、最佳适应算法或最坏适应算法。
模拟内存的分配和回收过程,观察内存的使用情况和碎片产生的情况。
2、虚拟内存管理了解 Windows 操作系统的虚拟内存机制,通过查看系统性能监视器观察虚拟内存的使用情况。
编写程序来模拟虚拟内存的页面置换算法,如先进先出(FIFO)算法、最近最少使用(LRU)算法等。
(三)文件系统实验1、文件操作使用 C++语言对文件进行创建、读写、删除等操作。
观察文件在磁盘上的存储方式和文件目录的结构。
2、文件系统性能测试对不同大小和类型的文件进行读写操作,测量文件系统的读写性能。
分析影响文件系统性能的因素,如磁盘碎片、缓存机制等。
四、实验结果与分析(一)进程管理实验结果1、创建多个进程在创建多个进程的实验中,通过任务管理器可以观察到每个进程都有独立的进程 ID、CPU 使用率、内存占用等信息。
多个进程可以并发执行,提高了系统的资源利用率。
2、进程同步与互斥在生产者消费者问题的实验中,当使用正确的信号量机制时,生产者和消费者能够协调工作,不会出现数据不一致或死锁的情况。
操作系统实验报告内存分配学生学号:学生姓名:专业年级:(一)实验目的设计编写首次适应算法实现内存分配,每次从低位开始对内存进行检验分配。
(二)设计思想程序分配内存时每次从最低位开始检验是否有满足分配条件的空闲空间,有则把该进程分配到链表的最后(若在中间有足够空闲空间且与两者差大于最小分配的空间大小则分配到该空闲空间的后面,然后把原空闲空间减去已分配的大小);每次释放空间先检查所释放空间前后是否有空闲空间,有则将空间合并。
(三)主要数据结构及变量说明空间链表数据类型space:struct space{struct space *former; int address;int num; int size; int state; struct space *next;},记录内存空间相关属性;最小分配空间int size_min=10;定义空间链表为S:typedef struct space S;S的指针mem:S *mem;;数据类型struct space *former:链表头结点;数据类型struct space *next:链表尾节点;m存放系统内存空间总大小的值。
(四)流程图(五)运行结果(六)附录(代码):#include<stdio.h>#include<stdlib.h>#include <iostream.h>struct space{struct space *former;int address;int num;int size;int state;struct space *next;};typedef struct space S;S *mem;int size_min=10;int m;void init(){mem=new S;mem->size=m;mem->former=0;mem->next=0;}void alloc(S *ptr,S *assign){if(ptr->next==NULL){if(ptr->size>=assign->size){ptr->size=ptr->size-assign->size;assign->state=1;ptr->next=assign;assign->former=ptr;}else{printf("没有足够的内存空间为进程%d分配\n",assign->num);delete assign;}}else{S *previous,*current;previous=ptr;current=previous->next;while(current!=NULL){if(current->size>=assign->size&¤t->state==0){break;}previous=current;current=current->next;}if(current==NULL){if(ptr->size>=assign->size){assign->address =m-(ptr->size);ptr->size=ptr->size-assign->size;assign->state=1;assign->former=previous;previous->next=assign;}else{printf("没有足够的内存空间为进程%d分配\n",assign->num);}}else{if((current->size-assign->size)<=size_min){current->num=assign->num;current->state=1;delete assign;}else{current->size=current->size-assign->size;assign->state=1;assign->address=current->address;current->address=assign->address+assign->size;current->former=assign;assign->next=current;assign->former=previous;previous->next=assign;}}}}void printgroup(S *ptr){S *temp;temp=ptr->next;printf("内存链的状态为:\n");while(temp!=NULL){if(temp->state==0){printf(" 起始地址为:%d",temp->address);printf(" 空闲空间大小为:%d",temp->size);printf(" 内存空闲\n");}else{printf("运行的进程:%d",temp->num);printf(" 起始地址为:%d",temp->address);printf(" 分配空间大小为:%d",temp->size);printf(" 内存已分配\n");}temp=temp->next;}}void free(S *ptr,int i){S *previous,*current;previous=ptr; current=previous->next;while(current!=NULL){if(current->state==1&¤t->num==i){break;}previous=current;current=current->next;}if(current==NULL){printf("内存中没有任何进程!!!\n");}else if(current->next==NULL){if(previous->state==0){previous->size=previous->size+current->size;previous->next=NULL;}else{current->state=0;}printf("进程%d释放%d的空间\n",current->num,current->size);printgroup(mem);}else{if(previous->state==0&&(current->next)->state==0){previous->size=previous->size+current->size+(current->next)->s ize;if((current->next)->next==NULL){previous->next=NULL;}else{((current->next)->next)->former=previous;previous->next=(current->next)->next;}}else if(previous->state==0){previous->size=previous->size+current->size;(current->next)->former=previous;previous->next=current->next;}else if((current->next)->state==0){current->size=current->size+(current->next)->size;current->state=0;if((current->next)->next==NULL){previous->next=NULL;}else{((current->next)->next)->former=current;current->next=(current->next)->next;}}else{current->state=0;}printf("进程%d释放%d的空间\n",current->num,current->size);printgroup(mem);}}void Creat(int i,int temp){printf("输入进程名和大小:\n");scanf("%d",&i);scanf("%d",&temp);space *fenpei;fenpei=(S *)malloc(sizeof(space));fenpei->former=NULL;fenpei->address=0;fenpei->size=temp;fenpei->num=i;fenpei->state=0;fenpei->next=NULL;alloc(mem,fenpei);printgroup(mem);}void main(void){int i;int j,k;printf("请输入内存大小:");scanf("%d",&m);init();while(1){printf("**************************\n");printf("申请内存输入数字1\n");printf("释放内存输入数字2\n");printf("中止进程输入数字0\n");printf("**************************\n");scanf("%d",&i);if(i==1){Creat(j,k);}if(i==2){printf("输入进程名:\n");scanf("%d",&j);free(mem,j);}if(i==0){break;}}}。
1. 理解内存分配的基本原理和方法;2. 掌握常见内存分配算法的实现过程;3. 分析不同内存分配算法的性能特点;4. 通过实验加深对内存管理机制的理解。
二、实验环境1. 操作系统:Windows 102. 编程语言:C语言3. 开发环境:Visual Studio 2019三、实验内容1. 内存分配算法本次实验主要实现了以下几种内存分配算法:(1)首次适应算法(First Fit):从空闲分区列表的头部开始查找,找到第一个足够大的分区进行分配。
(2)最佳适应算法(Best Fit):在所有空闲分区中,找到与请求大小最接近的分区进行分配。
(3)最坏适应算法(Worst Fit):在所有空闲分区中,找到最大的分区进行分配。
2. 内存分配过程实验中,我们模拟了一个简单的内存分配过程,包括以下步骤:(1)初始化内存:创建一个足够大的内存空间,并初始化为空闲状态。
(2)请求内存:模拟用户对内存的需求,以随机方式生成请求大小。
(3)内存分配:根据请求大小,选择合适的内存分配算法进行分配。
(4)内存回收:模拟用户释放内存的过程,将释放的内存空间重新标记为空闲状态。
1. 定义内存空间:创建一个足够大的数组来模拟内存空间。
2. 定义空闲分区链表:使用链表结构存储空闲分区信息,包括分区大小、起始地址等。
3. 实现内存分配算法:(1)首次适应算法:遍历空闲分区链表,找到第一个足够大的分区进行分配。
(2)最佳适应算法:遍历空闲分区链表,找到与请求大小最接近的分区进行分配。
(3)最坏适应算法:遍历空闲分区链表,找到最大的分区进行分配。
4. 实现内存回收功能:将释放的内存空间重新标记为空闲状态。
5. 测试内存分配算法:生成一系列随机请求大小,测试不同内存分配算法的性能。
五、实验结果与分析1. 首次适应算法:在请求内存时,算法效率较高,但可能会产生较多的外部碎片。
2. 最佳适应算法:在请求内存时,算法效率较低,但分配的内存空间利用率较高,外部碎片较少。