操作系统首次适应算法动态分配C语言代码
- 格式:docx
- 大小:535.01 KB
- 文档页数:10
操作系统的内存分配算法操作系统的内存管理是计算机系统中一个重要的组成部分。
内存分配算法决定了如何合理地利用系统的内存资源,以达到高效、安全、稳定的运行。
本文将介绍几种常见的内存分配算法,包括首次适应算法、循环首次适应算法、最佳适应算法以及快速适应算法。
首次适应算法(First Fit Algorithm)首次适应算法是一种简单而常见的内存分配算法。
它从内存空闲列表的头部开始寻找第一个适合分配的内存块。
当找到满足要求的内存块后,将该块划分为两部分,一部分用于分配给请求的程序,另一部分保留为剩余空闲块。
这种算法的优点是分配速度较快,缺点是可能会导致内存碎片的产生。
循环首次适应算法(Next Fit Algorithm)循环首次适应算法是首次适应算法的一种改进版本。
与首次适应算法不同的是,循环首次适应算法从上一次分配的位置开始搜索空闲块,直到找到一个满足要求的内存块为止。
这样可以避免每次都从头开始搜索,提高了查找的效率。
同样,这种算法也可能导致内存碎片的产生。
最佳适应算法(Best Fit Algorithm)最佳适应算法是为了解决内存碎片问题而提出的一种分配算法。
该算法会在内存空闲列表中查找最小且能满足要求的空闲块,并将该块分配给请求的程序。
这样可以尽量充分利用内存资源,减少内存碎片的产生。
但是,最佳适应算法的缺点是分配速度相对较慢,因为需要遍历整个内存空闲列表。
快速适应算法(Quick Fit Algorithm)快速适应算法是一种综合了首次适应算法和最佳适应算法的策略。
它将内存空闲列表分成了多个不同大小的链表,每个链表分别存储相应大小的空闲块。
当有程序请求内存时,快速适应算法会直接从对应大小的链表中查找可用的空闲块进行分配,以提高分配的速度。
这个算法在时间效率和空间效率上都较为出色,但是需要付出额外的存储开销。
总结不同的内存分配算法各有优缺点,选择合适的算法取决于具体的应用场景和系统需求。
首次适应算法和循环首次适应算法适用于内存分配需求频繁变化的场景。
第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. 创建一个动态内存分配模拟程序,包括空闲分区链表、分配函数和回收函数。
动态分区管理方式及动态分区算法一、动态分区概述在操作系统中,内存管理是一个非常重要的部分。
在实际的应用中,程序的内存需求是会发生变化的,因此需要一种灵活的内存管理方式来满足不同程序的内存需求。
动态分区管理方式应运而生,它可以根据程序的需求,灵活地分配和回收内存空间,是一种高效的内存管理方式。
二、动态分区管理方式动态分区管理方式是指将内存划分为多个大小不等的分区,每个分区都可以被分配给进程使用,当进程终止时,分区将被回收。
动态分区管理方式通常通过动态分区算法来实现,下面将介绍几种常见的动态分区算法。
三、首次适应算法首次适应算法是最简单和最直观的动态分区分配算法。
它的基本思想是在空闲分区链表中按照位置区域顺序查找第一个能够满足进程大小需求的空闲分区,并将其分配给进程。
首次适应算法的优点是实现简单,分区利用率较高,但缺点是会产生大量的不连续碎片。
四、最佳适应算法最佳适应算法是在空闲分区链表中查找满足进程大小需求的最小空闲分区,并将其分配给进程。
最佳适应算法的优点是可以减少外部碎片,缺点是查找适合的空闲分区会花费较长的时间。
五、最坏适应算法最坏适应算法是在空闲分区链表中查找满足进程大小需求的最大空闲分区,并将其分配给进程。
最坏适应算法的优点是能够产生较小的碎片,但缺点是会导致剩余分区较多,影响分区利用率。
六、动态分区管理方式的优缺点动态分区管理方式相比于静态分区管理方式有很多优点,比如可以灵活地满足不同程序的内存需求,可以动态地合并和分割分区,提高了内存的利用率等。
但是动态分区管理方式也有一些缺点,比如会产生碎片,分配和回收内存的开销较大等。
七、结语动态分区管理方式及其算法在实际应用中有着广泛的应用,通过合理选择动态分区算法,可以提高内存的利用率,改善系统性能。
也需要注意动态分区管理方式可能产生的碎片问题,可以通过内存紧缩等手段来解决。
希望本文对读者有所帮助。
动态分区管理方式及动态分区算法八、碎片问题与解决方法在动态分区管理方式中,经常会出现碎片问题,包括内部碎片和外部碎片。
学号专业姓名实验日期教师签字成绩实验报告【实验名称】采用可变式分区管理,使用首次获最佳适应算法实现内存分配与回收【实验目的与原理】1、理解首次获最佳适应算法的内涵,并熟练掌握该算法。
2、学会可变式分区管理的原理是即在处理作业过程中建立分区,使分区大小正好适合作业的需要,并且分区个数是可以调整的。
3、当有一个新作业要求装入主存时,必须查空闲区说明表,从中找出一个足够大的空闲区没有时应将空闲区一分为二。
为了便于快速查找,要不断地对表格进行紧缩,即让“空表目”项留在表的后部。
4、当一个作业执行完成时,作业所占用的分区应归还给系统。
作业的释放区与空闲区的邻接分以下四种情况考虑:①释放区下邻(低地址邻接)空闲区;②释放区上邻(高地址邻接)空闲区③释放区上下都与空闲区邻接;④释放区与空闲区不邻接。
【实验内容】#include<stdio.h>#include<iostream>#include<string>using namespace std;const int MAXJOB=100;//定义表最大记录数typedef struct node{int front;int length;char data[20];}job;job frees[MAXJOB];//定义空闲区表int free_quantity;job occupys[MAXJOB];//定义已分配区表int occupy_quantity;//初始化函数void initial(){int i;for(i=0;i<MAXJOB;i++){frees[i].front=-1;frees[i].length=0;strcpy(frees[i].data,"free");occupys[i].front=-1;occupys[i].length=0;strcpy(occupys[i].data," ");}free_quantity=0;occupy_quantity=0;}//创建空闲分区表int creatfree(){FILE *fp;char fname[20];cout<<"请输入空闲区数据文件来源的文件名:"; cin>>fname;if((fp=fopen(fname,"r"))==NULL){cout<<"错误,文件打不开,请检查文件名"<<endl; }else{while(!feof(fp)){fscanf(fp,"%d\t%d\n",&frees[free_quanti ty].front,&frees[free_quantity].length);free_quantity++;}cout<<"空闲的分区表已建立!\n";return 1;}return 0;}void sort()//将free空间安首地址从小到大的顺序排列{int i,j,p;for(i=0;i<free_quantity-1;i++){p=i;for(j=i+1;j<free_quantity;j++){if(frees[j].front<frees[p].front){p=j;}}if(p!=i){frees[free_quantity]=frees[i];frees[i]=frees[p];frees[p]=frees[free_quantity];}}}//显示函数void show(){int i;cout<<endl<<"----------------------------------------------------------"<<endl;cout<<"当前空闲表:"<<endl;cout<<" 起始地址长度状态"<<endl;for(i=0;i<free_quantity;i++){cout.setf(2);cout.width(12);cout<<frees[i].front;cout.width(10);cout<<frees[i].length;cout.width(8);cout<<frees[i].data<<endl;}cout<<endl<<"----------------------------------------------------------"<<endl;cout<<"当前已分配表:"<<endl;cout<<" 起始地址长度占用作业名"<<endl;for(i=0;i<occupy_quantity;i++){cout.setf(2);cout.width(12);cout<<occupys[i].front;cout.width(10);cout<<occupys[i].length;cout.width(8);cout<<occupys[i].data<<endl;}cout<<endl<<"----------------------------------------------------------"<<endl;}//最先适应分配算法void assign(){char job_name[20];int job_length;int i,j,flag,t;cout<<"请输入新申请内存空间的作业名和空间大小:";cin>>job_name;cin>>job_length;flag=0;for(i=0;i<free_quantity;i++){if(frees[i].length>=job_length)//如果空闲空间I的长度〉作业长度{flag=1; //空闲标志位就置1 }}if(flag==0){cout<<endl<<"对不起,当前没有能满足你申请长度的空闲内存,请稍候再试!"<<endl;}else{t=0;i=0;while(t==0)//为空闲区间的时候{if(frees[i].length>=job_length){t=1;}i++;//如果空闲空间I的长度不大于作业长度,I加一,判断下一个空间}i--;occupys[occupy_quantity].front=frees[i] .front;strcpy(occupys[occupy_quantity].data,jo b_name);occupys[occupy_quantity].length=job_len gth;occupy_quantity++;if(frees[i].length>job_length)//如果空间的长度大于作业的长度,{frees[i].front+=job_length;frees[i].length-=job_length;}else{for(j=i;j<free_quantity-1;j++){frees[j]=frees[j+1];}free_quantity--;cout<<"内存空间成功:)"<<endl;}}}//撤消作业void cancel(){char job_name[20];int i,j,flag,p=0;int front;int length;cout<<"请输入要撤消的作业名:";cin>>job_name;flag=-1;for(i=0;i<occupy_quantity;i++){if(!strcmp(occupys[i].data,job_name))//当输入作业名匹配时{flag=i;front=occupys[i].front;length=occupys[i].length;}}if(flag==-1){cout<<"没有这个作业名"<<endl;}else{//加入空闲表for(i=0;i<free_quantity;i++){if((frees[i].front+frees[i].length)==fr ont)//上空{if(((i+1)<free_quantity)&&(frees[i+1].f ront==front+length))//下空{frees[i].length=frees[i].length+frees[i +1].length+length;for(j=i+1;j<free_quantity;j++){frees[j]=frees[j+1];}free_quantity--;p=1;}else{frees[i].length+=length;p=1;}}if(frees[i].front==(front+length))//下空上不空{frees[i].front=front;frees[i].length+=length;//第i 个空闲区间的长度=第i个空闲区间的长度+lengthp=1;}}if(p==0)//上下空闲区都不空{frees[free_quantity].front=front;frees[free_quantity].length=length;free_quantity++;}//删除分配表中的该作业for(i=flag;i<occupy_quantity;i++){occupys[i]=occupys[i+1];}occupy_quantity--;}}void main(){int flag=0;int t=1;int chioce=0;cout<<"*********** xxxxxxxxx***********\n"; initial();flag=creatfree();while(flag==1){sort();cout<<" 可变分区存储管理模拟系统"<<endl;cout<<" 1.申请空间 "<<endl;cout<<" 2.撤消作业 "<<endl;cout<<" 3.显示空闲表和分配表"<<endl;cout<<" 0.退出"<<endl;cout<<"请选择:";cin>>chioce;switch(chioce){case 1:assign();break;case 2:cancel();break;case 3:show();break;case 0:flag=0;break;default:cout<<"选择错误!"<<endl;}}}实验结果显示:【实验小结】本实验难度在两个方面,一是首次最佳适应算法assign(),这里我用的是结构体数组来存储空闲分区;二是对已分配分区的释放,这里同样采取结构体数组来存储已分配分区,用cancle()函数来实现。
动态分区分配方式首次适应算法首次适应算法的思想是,当进程请求分配内存时,从空闲内存中找到第一个大小足够的空闲分区来满足进程需求。
因此,首次适应算法的时间复杂度与空闲分区的数量有关,但是分配成功的速度相对较快。
首先,我们需要建立一个空闲分区链表,其中记录了每个空闲分区的起始地址和大小。
初始状态下,整个内存空间是一个空闲分区。
当进程请求分配内存时,首次适应算法按照分区链表的顺序遍历空闲分区,找到第一个大小满足进程需求的分区。
具体操作如下:1.遍历空闲分区链表,找到第一个空闲分区大小大于等于进程请求大小的分区。
如果找到了满足条件的分区,则进行下一步;如果遍历完成仍未找到满足条件的分区,则进行内存紧缩或置换策略,为进程分配内存。
2.将找到的空闲分区进行分割,分为已分配给进程的部分和剩余的空闲部分。
已分配给进程的部分可以是与进程请求大小相等的分区,也可以是稍大的分区,以便于使用剩余空间。
3.更新空闲分区链表。
将已分配给进程的部分从链表中删除,将剩余的空闲分区插入链表中的适当位置。
4.返回已分配给进程的内存起始地址。
当进程释放内存时,可以通过合并相邻的空闲分区来优化内存空间的利用率。
1.遍历空闲分区链表,找到与释放的内存分区相邻的空闲分区。
2.将相邻的空闲分区进行合并,得到一个更大的空闲分区。
3.更新空闲分区链表。
首次适应算法的优点是简单有效,适用于动态内存分配的场景。
但是它也存在一些缺点,比如可能会造成内存碎片,不够高效地利用内存空间。
此外,首次适应算法相对于其他分配算法,如最佳适应算法和最坏适应算法,可能需要更多的时间来适合的空闲分区。
总结来说,首次适应算法是动态分区分配中常用的算法之一,其主要思想是按照分区链表的顺序第一个大小满足进程需求的空闲分区来分配内存。
虽然存在一些缺点,但在实际应用中,首次适应算法被广泛使用。
首次适应算法、循环首次适应算法、最佳适应算法和最坏适应算法是关于操作系统内存管理中内存分配策略的四种典型算法。
以下是对它们的简要解释:1. 首次适应算法(First-fit):在内存分配时,首次适应算法从内存区域的起始部分开始搜索,找到第一个能满足请求大小的空闲内存块,并将其分配给请求者。
首次适应算法的优点是分配速度较快,但可能导致内存空间碎片化。
2. 循环首次适应算法(Next-fit):循环首次适应算法类似于首次适应算法,但它在内存分配时保留上一次搜索的位置。
下一次分配时,算法将从上次停止的位置开始搜索,直到找到合适的空闲内存块或返回到起始位置。
这种方法可以在整个内存空间中分散分配过程,进一步改善内存碎片化问题。
3. 最佳适应算法(Best-fit):最佳适应算法在分配内存时,会查找所有可用的空闲内存块,并分配能够最紧密地满足请求大小的内存块。
该策略试图使分配后的剩余空间尽量小,以减少内存浪费。
然而,最佳适应算法通常需要更多的搜索时间,并可能导致过多的小内存碎片。
4. 最坏适应算法(Worst-fit):最坏适应算法与最佳适应算法相反,它在分配内存时选择最大的可用内存块。
这种策略试图保持较大的连续空闲内存块,以便满足大型请求。
然而,最坏适应算法可能导致大量空间浪费,并需要较长的搜索时间。
这些内存分配算法都有各自的优缺点。
在实际的操作系统实现中,可能会根据需求和上下文使用多种算法的组合来优化内存管理。
c模拟内存分配算法(⾸次适应算法,最佳适应算法,最坏适应算法)#include<bits/stdc++.h>using namespace std;/*定义内存的⼤⼩为100*/#define MEMSIZE 100/*如果⼩于此值,将不再分割内存*/#define MINSIZE 2/*内存分区空间表结构*/typedef struct _MemoryInfomation{/*起始地址*/int start;/*⼤⼩*/int Size;/*状态 F:空闲(Free) U:占⽤(Used) E 结束(End)*/char status;} MEMINFO;/*内存空间信息表*/MEMINFO MemList[MEMSIZE];/*显⽰内存状态*/void Display(){int i,used=0;//记录可以使⽤的总空间量printf("\n---------------------------------------------------\n");printf("%5s%15s%15s%15s","Number","start","size","status");printf("\n---------------------------------------------------\n");for(i=0; i<MEMSIZE&&MemList[i].status!='e'; i++){if(MemList[i].status=='u'){used+=MemList[i].Size;}printf("%5d%15d%15d%15s\n",i,MemList[i].start,MemList[i].Size,MemList[i].status=='u'?"USED":"FREE");}printf("\n----------------------------------------------\n");printf("Totalsize:%-10d Used:%-10d Free:%-10d\n",MEMSIZE,used,MEMSIZE-used);}/*初始化所有变量*/void InitMemList(){int i;MEMINFO temp= {0,0,'e'};//初始化空间信息表for(i=0; i<MEMSIZE; i++){MemList[i]=temp;}//起始地址为0MemList[0].start=0;//空间初始为最⼤MemList[0].Size=MEMSIZE;//状态为空闲MemList[0].status='f';}/*最先适应算法*//*算法原理分析:将空闲的内存区按其在储存空间中的起始地址递增的顺序排列,为作业分配储存空间时,从空闲区链的始端开始查找,选择第⼀个满⾜要求的空闲区,⽽不管它究竟有多⼤优点:1.在释放内存分区的时候,如果有相邻的空⽩区就进⾏合并,使其成为⼀个较⼤的空⽩区2.此算法的实质是尽可能的利⽤储存器的低地址部分,在⾼地址部分则保留多的或较⼤的空⽩区,以后如果需要较⼤的空⽩区,就容易满⾜缺点:1.在低地址部分很快集中了许多⾮常⼩的空⽩区,因⽽在空⽩区分配时,搜索次数增加,影响⼯作效率。
动态分区分配算法仿真,循环首次适应算法、最佳适应算法、最坏适应算法#include<iostream>#include<iomanip>//在输入输出流中用到控制符#include<windows.h>//用到了SetConsoleTextAttribute函数#define minsize 2//事先规定的不再切割的剩余分区大小为2using namespace std;struct Node{int name;int start;int size;int state;Node *pre;Node *next;};typedef struct Dlinklist{Node *head;}Dlist;//===================Dlist pro,fre;int memory,name,size,fit;Node *temp=NULL;//temp是NestFit算法中的起始查寻指针//===================void initDlist(Dlist &L)//创建带有头结点的双向链表{L.head=new Node;L.head->next=L.head->pre=NULL;}void MemoryInit()//初始化两个链表{initDlist(pro); //process链表initDlist(fre); //free block链表Node *p=new Node;p->name=0;p->start=0;p->state=0;p->size=memory;p->next=NULL;//这里曾错写成p->pre..............p->pre=fre.head;//这里曾漏写fre.head->next=p;}int getLength(Dlist &L)//返回链表的长度,即元素的个数int m=0;Node *p=L.head->next;while(p!=NULL){m++;p=p->next;}return m;}void arrangeSmaller(Dlist &L)//冒泡排序,链表按size进行排序,从小到大{int length=getLength(L);for(int i=0; i<length-1; i++)//当链表中的元素个数>=2的时候才排序{Node *p=L.head->next;Node *q=p->next;inta,b,c,d;//===================================================================== =====for(int j=0; j<length-1-i; j++){if(p->size>q->size) //交换位置,如果前面的大于后面的,使小的上浮,如果两个相等,则还是原来在前的保持在前{a=p->size;p->size=q->size;q->size=a;b=p->name;p->name=q->name;q->name=b;c=p->start;p->start=q->start;q->start=c;d=p->state;//============================================================== ============p->state=q->state;q->state=d;}p=p->next;q=p->next;}}void arrangeBigger(Dlist &L)//链表按size进行排序,从大到小{int length=getLength(L);for(int i=0; i<length-1; i++){Node *p=L.head->next;Node *q=p->next;int a,b,c,d;for(int j=0; j<length-1-i; j++){if(p->size<q->size){a=p->size;p->size=q->size;q->size=a;b=p->name;p->name=q->name;q->name=b;c=p->start;p->start=q->start;q->start=c;d=p->state;//============================================================== ============p->state=q->state;q->state=d;}p=p->next;q=p->next;}}}void arrangeStart(Dlist &L)//链表按start递增排序{int length=getLength(L);for(int i=0; i<length-1; i++){Node *p=L.head->next;Node *q=p->next;int a,b,c,d;for(int j=0; j<length-1-i; j++){if(p->start>q->start){a=p->size;p->size=q->size;q->size=a;b=p->name;p->name=q->name;q->name=b;c=p->start;p->start=q->start;q->start=c;d=p->state;//============================================================== ============p->state=q->state;q->state=d;}p=p->next;q=p->next;}}}void DlistInsert(Dlist &L,Node e) //在头结点之后插入元素,即L.head->next指向e {Node *p=new Node;p->name=;p->size=e.size;p->start=e.start;p->state=e.state;if(L.head->next!=NULL)//这是个值得注意的地方,L.head->next==NULL,则没有指针L.head->next->pre,如果这里不加判断的话,会出错L.head->next->pre=p;p->next=L.head->next;p->pre=L.head;L.head->next=p;//双向链表,插入一个新的元素,如果元素不是插入在链尾,则一共要修改四次指针}void DlistDelete(Node *p,Node &e)//传递指针p,删除指针p指向的链表元素,用Node 型变量e记录该元素的相关数据{=p->name;e.start=p->start;e.size=p->size;e.state=p->state;p->pre->next=p->next;//这里曾写成=p->pre....if(p->next!=NULL)p->next->pre=p->pre;//这里曾写成p->next->pre=p,留意delete(p); //删除一个元素修改一次或两次指针}//=======================void Green(){SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSIT Y|FOREGROUND_GREEN);}void Red(){ SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSIT Y|FOREGROUND_RED);}void White(){SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_RED|FORE GROUND_GREEN|FOREGROUND_BLUE);}void Yellow(){SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSIT Y|FOREGROUND_RED|FOREGROUND_GREEN);}//=======================void BestOrWorst(){arrangeStart(fre);//先按地址递增排序if(fit==1)arrangeSmaller(fre);//再按size递增排序,当两个空闲区的size一样时,由于先按地址递增排序了,所以还是地址低的在前。
实验报告
系别班级学号姓名时间地点
计算机科学系计科1201 2014/12/29 机房 c105 课程名称计算机操作系统实验名称存管理
实验过程
四.运行截图
五.实验总结
算法要求空闲链已地址递增的次序连接。
分配存时,从链首开始顺序查找,直到找到第一个满足要求的空间并分配给进程,把分配后余下的空间仍然留在链表中。
若从链首至链尾都不满足要求,则分配失败。
该算法倾向于优先使用低地址的空间,在不断分割中会产生很多空间碎片,并且每次都是从链首开始查找,这无疑增加了开销。
⾸次适应与循环⾸次适应算法实现⼀、实验内容编程实现⾸次适应与循环⾸次适应算法。
⼆、实验要求1.任选⼀种⾼级语⾔实现;三、实验过程1、 设计思想⾸次适应算法(FF):将所有空闲分区按照地址递增的次序链接,在申请内存分配时,从链⾸开始查找,将满⾜需求的第⼀个空闲分区分配给作业。
循环⾸次适应算法(NF):将所有空闲分区按照地址递增的次序链接,在申请内存分配时,总是从上次找到的空闲分区的下⼀个空闲分区开始查找,将满⾜需求的第⼀个空闲分区分配给作业2、 数据结构public class FreeArea {private int address;//内存地址private int size;//空闲区⼤⼩public FreeArea() {}public FreeArea(int address, int size) {this.address = address;this.size = size;}public int getAddress() {return address;}public void setAddress(int address) {this.address = address;}public int getSize() {return size;}public void setSize(int size) {this.size = size;}}4、运⾏结果:四、实验代码RR.Hpackage com.hu;import java.util.Scanner;public class MemoAlloc {public static void main(String[] args) {System.out.println("======⾸次适应算法======");FreeArea freeArea[]= init();FF(freeArea);System.out.println("=====循环⾸次适应算法=====");FreeArea freeArea1[]= init();NF(freeArea1);}public static void FF(FreeArea freeArea[]){//⾸次适应算法Scanner scanner = new Scanner(System.in);System.out.println("请输⼊要分配的内存⼤⼩:");int size = scanner.nextInt();for (int i =0;i<freeArea.length;i++){if (size<=freeArea[i].getSize()){//若分配内存⼤⼩⼩于空闲分区⼤⼩则分配成功System.out.println("分配内存成功");freeArea[i].setSize(freeArea[i].getSize()-size);//修改空闲分区⼤⼩break;}if (i== freeArea.length-1&&size>freeArea[i].getSize()) System.out.println("分配失败");}}public static void NF(FreeArea freeArea[]){//循环⾸次适应Scanner scanner = new Scanner(System.in);System.out.println("请输⼊要分配的内存⼤⼩:");int size = scanner.nextInt();boolean isWhile=true;int ProcessNum =0;int j=0;for (int i=ProcessNum;i< freeArea.length;i++,j++){if (size <= freeArea[i].getSize() ) {//若分配内存⼤⼩⼩于空闲分区⼤⼩则分配成功System.out.println("分配内存成功");freeArea[i].setSize(freeArea[i].getSize() - size);ProcessNum = j+1;//下⼀次查找时从本次找到的空闲分区的下⼀个分区开始找break;}else if (ProcessNum!=0 && i== freeArea.length-1&&size>freeArea[i].getSize()){ProcessNum=0;//若开始查找时不是从链⾸开始,最后⼀个空闲分区⼤⼩仍不能满⾜要求,则返回第⼀个空闲分区}else if(ProcessNum==0&&i== freeArea.length-1&&size>freeArea[i].getSize()){System.out.println("分配失败");//若开始查找时是从链⾸开始,最后⼀个空闲分区⼤⼩仍不能满⾜要求,则分配失败};}}public static FreeArea[] init(){//空闲区初始化并排序System.out.println("初始化空闲区并分配内存地址与⼤⼩");Scanner scanner = new Scanner(System.in);FreeArea[] freeAreas = new FreeArea[5];for (int i=0;i<freeAreas.length;i++){System.out.println("请输⼊内存地址与⼤⼩:");freeAreas[i] = new FreeArea(scanner.nextInt(),scanner.nextInt());}FreeArea t;for (int i = 0;i<freeAreas.length;i++){for (int j = 0;j<freeAreas.length-1;j++){if(freeAreas[j].getAddress()>freeAreas[j+1].getAddress()){t = freeAreas[j+1];freeAreas[j+1]=freeAreas[j];freeAreas[j]=t;}}}return freeAreas;}}五、实验总结通过本次实验我更加了解了循环⾸次适应与⾸次适应算法,⾸次适应算法优先利⽤低地址部分空闲分区,保留了⾼地址部分的⼤空闲区,缺点是低址部分不断被划分,会留下很多难以利⽤的⼩的外部碎⽚,每次都从低地址部分开始查会增加查找时的开销。
实验名称:操作系统动态分配*名:***学号:**********专业班级:创新实验班111 指导老师:**实验题目内存动态分区的分配与回收内存实验目的有利于我们更好的了解内存动态分区分配的操作情况,掌握可变分区首次适应算法的原理以及其编程实现。
设计思想可变分区分配是根据进程的实际需求,动态地为之分配内存空间。
首次适应算法要求空闲空间链以地址递增的次序链接。
进行内存分配时,从链表头部开始依次检索,找到第一个不小于请求空间大小的空闲空间进行分配。
分配时需考虑碎片问题,若分配会导致碎片产生则将整块分区分配。
内存的回收需要考虑四种情况:⑴收分区前后两个分区都空闲,则需要和前后两个分区合并;⑵回收分区只有前一分区空闲,则与前一分区合并;⑶回收分区只有后一分区空闲,则和后一分区合并;⑷回收分区独立,不考虑合并主要数据结构主要的数据结构有两个:空闲分区表结构和表的链结构。
根据空闲分区的作用,空闲分区表结构必须包括(分区号、分区起始地址、分区状态、分区数据大小)。
由于采用的是双向链表的结果,所以表的链结构包括(空闲分区表的信息、首指针、尾指针)结构程序代码如下:typedef struct Body{int ID;int size;int address;int sign;};typedef struct Node{Body data;struct Node *prior;struct Node *next;}*DLinkList;流程图退出选0 输入有误 >3 or<0 选择0-3操作 操作界面 开始 选3 显示内存分配 选2 回收内存 选1 分配内存运行结果图(1)主界面图(2)分配3个分区后的分配情况图(3)回收1、3分区后的分配情况图(4)再次分配4分区后的分配情况附录:源代码如下:#include<iostream.h>#include<stdio.h>#define Free 0 //空闲#define Zhanyong 1 //占用#define FINISH 1 //完成#define ERROR 0 //出错#define memory 512 //最大内存#define min 10 //碎片值typedef struct Body{int ID;int size;int address;int sign;};typedef struct Node{Body data;struct Node *prior;struct Node *next;}*DLinkList;DLinkList head; //头结点DLinkList tou; //尾结点int Create()//初始化{head=(DLinkList)malloc(sizeof(Node));tou=(DLinkList)malloc(sizeof(Node));head->prior=NULL;head->next=tou;tou->prior=head;tou->next=NULL;tou->data.address=0;tou->data.size=memory;tou->data.ID=0;tou->data.sign=Free;return FINISH;}int FirstFit(int ID,int space)//首次适应算法{DLinkList NewNode=(DLinkList)malloc(sizeof(Node));//新建作业的结点NewNode->data.ID=ID;NewNode->data.size=space;NewNode->data.sign=Zhanyong;Node *p=head;while(p){if(p->data.sign==Free && p->data.size==space)//剩余大小恰好满足{{p->data.sign=Zhanyong;p->data.ID=ID;return FINISH;break;}if(p->data.sign==Free && p->data.size>space && (p->data.size-space>min))//满足需求且有剩余且不产生碎片{NewNode->prior=p->prior;NewNode->next=p;NewNode->data.address=p->data.address;p->prior->next=NewNode;p->prior=NewNode;p->data.address=NewNode->data.address+NewNode->data.size;p->data.size=p->data.size-space;return FINISH;break;}if(p->data.sign==Free && p->data.size>space && p->data.size-space<=min)//产生碎片时{p->data.sign=Zhanyong;p->data.ID=ID;return FINISH;break;}p=p->next;//若已有分配,P指针后移}return ERROR;}int Allocation()//内存分配{int ID,space;printf("请输入分区号(不能输入相同的两个分区号):");scanf("%d",&ID);printf("输入分配内存大小(单位:KB):");scanf("%d",&space);if(space<0 ||space==0){printf("分配的内存大小必须是正整数!\n");return ERROR;}if(FirstFit(ID,space)==FINISH)printf("分配成功!\n");elseprintf("内存不足,分配失败!\n");}int Recycle(int ID)//shifangzuoye{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;}printf("分区号为%d的内存回收成功\n",ID);return FINISH;}void show(){printf("************************当前内存分配情况*************************\n");Node *p=head->next;while(p){printf("分区号:");if(p->data.ID==Free)printf("未分配");elseprintf("%6d",p->data.ID);printf(" 始地址:%4d",p->data.address);printf(" 分区大小:%4dKB",p->data.size);printf(" 状态:");if(p->data.sign==Free)printf("空闲\n");else if(p->data.sign==Zhanyong)printf("已分配\n");p=p->next;}printf("\n");}int main(){Create();int choice;int i;for(i=0;;i++){printf("请选择操作:\n");printf("1.分配内存\n");printf("2.回收内存\n");printf("3.显示内存分配情况\n");printf("0.退出程序\n");scanf("%d",&choice);if(choice==1)Allocation();else if(choice==2){ i nt ID;printf("输入要回收的分区号:");scanf("%d",&ID);Recycle(ID);}else if(choice==3)show();else if(choice==0)break;else{printf("输入有误!\n");continue;}}}。