操作系统实验2—实现动态分区分配模拟程序

文章目录

  • 操作系统实验2—实现动态分区分配模拟程序
    • 实验描述
    • 设计思路
    • 上机代码
    • 测试结果
    • 心得体会

实验描述

实验内容:

编写一个可变分区存储管理程序,模拟可变分区存储管理方式下对内存空间的动态分配与回收。

实验目的:

内存管理是操作系统中的核心模块,能够合理利用内存,在很大程度上将影响到整个计算机系统的性能。内存的分配和回收与内存管理方式有关。本实验要求学生独立设计并实现可变分区管理方式下的内存分配与回收模拟程序,以加深对各种分配回收算法和可变分区存储管理方式及其实现过程的理解。

实验要求:

1.可以随机输入初始可用内存空间容量,以及进程对内存空间的请求序列,支持首次适应算法、最佳适应算法和最坏适应算法,能够在每次内存分配和回收操作后,显示内存空间的使用情况。具体信息见测试用例格式说明。

2.空闲分区通过空闲区链进行管理,在内存分配时,优先考虑低地址部分的空闲区。

3.当申请空间大于可用空闲内存空间时,不满足此次申请,仍显示此次申请前内存空间的使用情况,后续也不再对此次申请进行任何处理。

4.进程对内存空间的申请和释放可由用户自定义输入。例如,与测试用例示例输入对应的内存空间请求序列为:

(1) 初始状态下可用内存空间为640KB;

(2) 进程1申请130KB;

(3) 进程2申请60KB;

(4) 进程3申请100KB;

(5) 进程2释放60KB;

(6) 进程4申请200KB;

(7) 进程3释放100KB;

(8) 进程1释放130KB;

(9) 进程5申请140KB;

(10) 进程6申请60KB;

(11) 进程7申请50KB;

(12) 进程6释放60KB。

5.分别采用首次适应算法、最佳适应算法和最坏适应算法模拟内存空间的动态分配与回收,每次分配和回收后显示出内存空间的使用情况(参见测试用例示例输出)。

测试用例格式如下:

输入:

动态分区分配算法选择
可用内存空间容量
序号/进程号/申请或释放操作/申请或释放的容量

其中:
(1) 动态分区分配算法:

  1. 首次适应
  2. 最佳适应
  3. 最坏适应

(2) 申请或释放操作:

  1. 申请操作
  2. 释放操作

输出:

序号/内存空间状态1/内存空间状态2…

其中,内存空间状态表示分为两种情况:

(1) 内存空间被占用:

  内存空间起始地址-内存空间结束地址.1.占用的进程号

(2) 内存空间空闲

  内存空间起始地址-内存空间结束地址.0

测试用例示例如下:

测试输入 期待的输出 时间限制 内存限制 额外进程
测试用例 1 1
640
1/1/1/130
2/2/1/60
3/3/1/100
4/2/2/60
5/4/1/200
6/3/2/100
7/1/2/130
8/5/1/140
9/6/1/60
10/7/1/50
11/6/2/60
1/0-129.1.1/130-639.0
2/0-129.1.1/130-189.1.2/190-639.0
3/0-129.1.1/130-189.1.2/190-289.1.3/290-639.0
4/0-129.1.1/130-189.0/190-289.1.3/290-639.0
5/0-129.1.1/130-189.0/190-289.1.3/290-489.1.4/490-639.0
6/0-129.1.1/130-289.0/290-489.1.4/490-639.0
7/0-289.0/290-489.1.4/490-639.0
8/0-139.1.5/140-289.0/290-489.1.4/490-639.0
9/0-139.1.5/140-199.1.6/200-289.0/290-489.1.4/490-639.0
10/0-139.1.5/140-199.1.6/200-249.1.7/250-289.0/290-489.1.4/490-639.0
11/0-139.1.5/140-199.0/200-249.1.7/250-289.0/290-489.1.4/490-639.0
1秒 64M 0
测试用例 2 2
640
1/1/1/130
2/2/1/60
3/3/1/100
4/2/2/60
5/4/1/200
6/3/2/100
7/1/2/130
8/5/1/140
9/6/1/60
10/7/1/50
11/6/2/60
1/0-129.1.1/130-639.0
2/0-129.1.1/130-189.1.2/190-639.0
3/0-129.1.1/130-189.1.2/190-289.1.3/290-639.0
4/0-129.1.1/130-189.0/190-289.1.3/290-639.0
5/0-129.1.1/130-189.0/190-289.1.3/290-489.1.4/490-639.0
6/0-129.1.1/130-289.0/290-489.1.4/490-639.0
7/0-289.0/290-489.1.4/490-639.0
8/0-289.0/290-489.1.4/490-629.1.5/630-639.0
9/0-59.1.6/60-289.0/290-489.1.4/490-629.1.5/630-639.0
10/0-59.1.6/60-109.1.7/110-289.0/290-489.1.4/490-629.1.5/630-639.0
11/0-59.0/60-109.1.7/110-289.0/290-489.1.4/490-629.1.5/630-639.0
1秒 64M 0
测试用例 3 3
640
1/1/1/130
2/2/1/60
3/3/1/100
4/2/2/60
5/4/1/200
6/3/2/100
7/1/2/130
8/5/1/140
9/6/1/60
10/7/1/50
11/6/2/60
1/0-129.1.1/130-639.0
2/0-129.1.1/130-189.1.2/190-639.0
3/0-129.1.1/130-189.1.2/190-289.1.3/290-639.0
4/0-129.1.1/130-189.0/190-289.1.3/290-639.0
5/0-129.1.1/130-189.0/190-289.1.3/290-489.1.4/490-639.0
6/0-129.1.1/130-289.0/290-489.1.4/490-639.0
7/0-289.0/290-489.1.4/490-639.0
8/0-139.1.5/140-289.0/290-489.1.4/490-639.0
9/0-139.1.5/140-199.1.6/200-289.0/290-489.1.4/490-639.0
10/0-139.1.5/140-199.1.6/200-289.0/290-489.1.4/490-539.1.7/540-639.0
11/0-139.1.5/140-289.0/290-489.1.4/490-539.1.7/540-639.0
1秒 64M 0

设计思路

输入的进程序列有序号、进程号、执行操作类型、所需内存四个属性,毫无疑问,用结构体来存储是再合适不过了。用链表来模拟内存的分配,同样也有开始地址、结束地址等不少属性的存储,也是采用的结构体。

struct memory
{int startaddre;    //开始地址int endaddre; //结束地址int id;           //标记进程号int size;        //分区大小int state;        //是否被占进程用标记 0 表示未被占用,1 表示被占用struct memory * next;
};
typedef struct node
{int no;            //序号int id;         //进程号int operation; //执行操作int volume;       //进程所需内存内存
}PCB;

程序概要设计如下图所示:

  1. main()函数是主程序的入口,控制程序流程,按照输入的调度信号选择相应的算法模块进行运行,并输出相应的结果
  2. input()函数是输入函数,接受程序输入
  3. FF()函数是首次适应算法
  4. BF()函数是最佳适应算法
  5. WF()函数是最坏适应算法
  6. FFallocate()函数是 FF 算法的具体实现
  7. BFallocate()函数是 BF()函数的具体实现
  8. WFallocate()函数是 WF()函数的具体实现
  9. free_()函数的作用是释放分区
  10. output()函数是输出函数,输出分区链表状态
int main()                       //主函数入口
void FF(memory *p);             //首次适应
void BF(memory *p,memory *head);//最佳适应
void WF(memory *p,memory *head);//最坏适应
void FFallocate(PCB pc,memory *p);              //最先适应分配分区算法
void BFallocate(PCB pc,memory *p,memory *head) ;//最佳适应
void WFallocate(PCB pc,memory *p,memory *head) ;//最坏适应
void free_(PCB pc,memory *p);   //释放分区算法
void input() ;                  //输入进程序列
void output(PCB pc,memory *p) ; //输出分区链表状态函数

上机代码

代码使用 C++ 语言进行编写

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<string>
using namespace std;
struct memory
{int startaddre;//开始地址 int endaddre;//结束地址 int id;//标记进程号 int size;//分区大小 int state;//是否被占进程用标记 0 表示未被占用,1 表示被占用struct memory * next;
};typedef struct node
{int no;//序号 int id;//进程号 int operation;//执行操作 int volume;//进程所需内存内存
}PCB;
PCB pcb[1010];//输入进程数组
int sig=0;//算法标志
int num=0;//输入进程大小
int total;//内存容量
PCB pc; void FF(memory *p);//首次适应
void BF(memory *p,memory *head);//最佳适应
void WF(memory *p,memory *head);//最坏适应 void FFallocate(PCB pc,memory *p) ;//最先适应分配分区算法
void BFallocate(PCB pc,memory *p,memory *head) ;//最佳适应
void WFallocate(PCB pc,memory *p,memory *head) ;//最坏适应
void free_(PCB pc,memory *p);//释放分区算法
void input();//输入进程序列
void output(PCB pc,memory *p) ;//输出分区链表状态函数 int main()
{//程序输入 input();memory *head,*p;head = (memory*)malloc(sizeof(memory));//初始化head->next = NULL;head->size = total;head->startaddre = 0;head->endaddre = head->size + head->startaddre - 1;head->state = 0;p = head;//选择算法 switch (sig){case 1:FF(p);break;case 2:BF(p,head);break;case 3:WF(p,head);break;}return 0;
}
void input()
{// freopen("osin.txt", "r", stdin); // freopen("osout.txt", "w", stdout); sig = 0;cin >> sig;//算法选择标志total = 0;cin >> total;//输入可用容量num = 0;//输入进程序列while (~scanf("%d/%d/%d/%d", &pcb[num].no, &pcb[num].id, &pcb[num].operation, &pcb[num].volume)){num++;}
}
void output(PCB pc,memory *p)//输出分配区状态函数
{printf("%d",pc.no);while(p!=NULL){if(p->next!=NULL)//不是最后一个链表区 {if(p->state==1)  //内存被占用 printf("/%d-%d.%d.%d",p->startaddre,p->endaddre,p->state,p->id);elseprintf("/%d-%d.%d",p->startaddre,p->endaddre,p->state);}else //最后一个链表区 ,换行 {if(p->state==1)printf("/%d-%d.%d.%d\n",p->startaddre,p->endaddre,p->state,p->id);elseprintf("/%d-%d.%d\n",p->startaddre,p->endaddre,p->state);}p=p->next;}
}
void FFallocate(PCB pc,memory *p)   //首适应分配内存算法
{ while(p!=NULL)   //从链表首指针一直找到尾指针 {if((pc.volume<p->size)&&p->state==0)//进程未分配且能在分区分配这个进程 ,//将有剩余内存空间 ,相当于在后面插入节点 {p->id=pc.id;//分区记录下进程号 p->state=1;//标记被占用 p->endaddre=p->startaddre+pc.volume-1;memory *add;//增加一个链表add=(memory *)malloc(sizeof(memory));//在p后面插入add链表 add->startaddre=p->endaddre+1;add->size =p->size-pc.volume;add->endaddre=add->startaddre+add->size-1;add->state=0;add->next=p->next ;//插入 p->next=add;    //操作 p->size=pc.volume;break;}//进程未分配且能在分区分配这个进程 ,//没有剩余内存空间 ,只是占用标记位改变 else if(pc.volume==p->size&&p->state==0) {p->id=pc.id;//分区记录下进程号 p->state=1;//标记被占用break; }p=p->next;}
}void BFallocate(PCB pc,memory *p,memory *head)
{  int sub=-1;//分区链表内存与将要分配进程内存之差 int minsub=-1;//分区链表内存与将要分配进程内存之差最小值。//初始化为-1;int flag1=0;//标记是否是第一次适应 int location=0; //记录最小之差的链表位置 int len=0;//记录链表位置 while(p!=NULL){if(p->state==0&&(p->size-pc.volume)>=0) //链表区空闲且内存比进程所需内存大则可以存进程 {//不能把sub在if外面赋值,否则sub将一直>=0 sub=p->size-pc.volume;//链表区与进程所需内存之差 if(flag1==0)//第一个能存进程的链表 {minsub=sub;//此时内存之差 location=len; //记录链表位置 }else //从多个链表找出一个内存之差最小的{ if(sub<minsub){minsub=sub;location=len;//记录其下标}}flag1++;}len++;//表示链表位置后移 p=p->next;}if(minsub>=0) /*/能存入进程minsub才>=0 /*/{ int i;p=head;      //之前p指向链表尾指针,现在应该指向头指针 //从头开始寻找标志位 ,满足则 p指向它 for(i=0;i<location;i++) {p=p->next;//p指向能放入进程且两者内存之差最小的链表 }if(minsub>0){p->id=pc.id;//分区记录下进程号 p->state=1;//标记被占用 p->endaddre=p->startaddre+pc.volume-1;//尾地址为首地址加上进程内存大小-1 memory *add;//增加一个链表add=(memory *)malloc(sizeof(memory));//在p后面插入add链表 add->startaddre=p->endaddre+1;add->size =p->size-pc.volume;add->endaddre=add->startaddre+add->size-1;add->state=0;//表示未被占用 add->next=p->next ;p->next=add;p->size=pc.volume;}else{p->id=pc.id;//分区记录下进程号 p->state=1;//标记被占用} }
}
void WFallocate(PCB pc,memory *p,memory *head)
{  int sub=-1;//分区链表内存与将要分配进程内存之差 int maxsub=-1;//分区链表内存与将要分配进程内存之差最大值,//初始化为-1 int flag1=0;//标记是否是第一次适应 int location=0; //记录最小之差的链表位置 int len=0;//记录链表位置 while(p!=NULL){if(p->state==0&&(p->size-pc.volume)>=0) //链表区空闲且内存比进程所需内存大则可以存进程 {sub=p->size-pc.volume;//链表区与进程所需内存之差 if(flag1==0)//第一个能存进程的链表 {maxsub=sub;//此时内存之差 location=len; //记录链表位置 }else //从多个链表找出一个内存之差最小的{ if(sub>maxsub){maxsub=sub;location=len;//记录其下标}}flag1++;}len++;//表示链表位置后移 p=p->next;}if(maxsub>=0) /*/能存入进程maxsub才>=0 /*/{ int i;p=head;//之前p指向链表尾指针,现在应该指向头指针 //从头开始寻找标志位 ,满足则 p指向它 for(i=0;i<location;i++) {p=p->next;//p指向能放入进程且两者内存之差最小的链表 }if(maxsub>0){p->id=pc.id;//分区记录下进程号 p->state=1;//标记被占用 p->endaddre=p->startaddre+pc.volume-1;//尾地址为首地址加上进程内存大小-1 memory *add;//增加一个链表add=(memory *)malloc(sizeof(memory));//在p后面插入add链表 add->startaddre=p->endaddre+1;add->size =p->size-pc.volume;add->endaddre=add->startaddre+add->size-1;add->state=0;//表示未被占用 add->next=p->next ;p->next=add;p->size=pc.volume;}else{p->id=pc.id;//分区记录下进程号 p->state=1;//标记被占用} }
}void free_(PCB pc,memory *p)
{int count=0; memory *pp,*pnext;//链表长度大于1时,pp是p上一个链表 while(p!=NULL){if(p->id==pc.id)  //遍历找到将要释放的进程位置 {if(count==0) //释放的分配区在链表首部 {if(p->next!=NULL){pnext=p->next;if(pnext->state==0){p->state=0;//标记进程未被占用 //删除q节点,p节点大小和末地址增加 p->next=pnext->next;p->size+=pnext->size;p->endaddre=pnext->endaddre;free(pnext);break;}else{p->state=0;break;}}else{p->state=0;//标记进程未被占用 break;}}else if(p->next!=NULL)//释放的分配区在链表中间 {pnext=p->next;if(pp->state==1&&pnext->state==1)//前后链表区都有进程占用{p->state=0;//只把进程占用标记置为 0break;}//只是后面链表区被占用 //合并内存,删除p指向节点 else if(pp->state==0&&pnext->state==1) {pp->next=p->next;pp->size+=p->size;pp->endaddre=p->endaddre;free(p);break;}//只是前面链表区被占用 //合并内存,删除p指向节点 else if(pp->state==1&&pnext->state==0) {pp->next=p->next;pnext->size+=p->size;pnext->startaddre=p->startaddre;free(p);break;}//前后链表区都不被占用//合并内存,删除p指向节点和p后面一个节点else if(pp->state==0&&pnext->state==0) {pp->next=pnext->next;pp->size+=p->size+pnext->size;pp->endaddre=pnext->endaddre;free(p);free(pnext);break;}    }else if(p->next==NULL)//释放的分配区在链表尾{if(pp->state==1)//前一个链表区不为空 {p->state=0;break;}else //前一个链表区为空 {pp->next=p->next;pp->state=0;pp->size+=p->size;pp->endaddre=p->startaddre;free(p);break;}}              }pp=p; //pp指向下次遍历的p指向的前一个节点 p=p->next; count++;  }
}void FF(memory *p)//首次适应
{int i=0;for(i=0;i<num;i++)//是否每个进程分配或释放完 {if(pcb[i].operation==1) {FFallocate(pcb[i],p);output(pcb[i],p) ;} else //(pcb[i].operation==2){free_(pcb[i],p);output(pcb[i],p);} }
}
void BF(memory *p,memory *head) //最佳适应
{int i=0;for(i=0;i<num;i++)//是否每个进程分配或释放完 {if(pcb[i].operation==1) {BFallocate(pcb[i],p,head);output(pcb[i],p) ;} else //(pcb[i].operation==2){free_(pcb[i],p);output(pcb[i],p);}    }
}void WF(memory *p,memory *head) //最坏适应
{int i=0;for(i=0;i<num;i++)//是否每个进程分配或释放完 {if(pcb[i].operation==1) {WFallocate(pcb[i],p,head);output(pcb[i],p) ;} else //(pcb[i].operation==2){free_(pcb[i],p);output(pcb[i],p);}    }
}

测试结果

程序采用黑盒测试的方式,提交到 OJ 系统上进行在线评测

可以看到,OJ 的测试用例全部通过

心得体会

通过本次实验,上机代码模拟实现了三种动态分区分配算法,对操作系统内部的空闲分区分配方式有了更深刻的认识和感受。FF 首次适应算法在低址部分不断被划分,会留下很多难以利用的、很小的空闲碎片。BF 最佳适应算法似乎是最优的,但是可能会在存储器中留下许多难以利用的碎片。WF 最坏适应算法与最佳适应算法刚好相反,它会导致存储器中缺乏大的空闲分区,但是未必是最坏的,它产生碎片的可能性最小。

操作系统实验2—实现动态分区分配模拟程序相关推荐

  1. 操作系统 实验3【动态分区存储管理】

    操作系统 实验1[短作业优先调度算法(C++实现--FCFS\SJF\HRRN)] 操作系统 实验2[动态高优先权优先调度算法 C++实现] 操作系统 实验3[动态分区存储管理 Python实现] 操 ...

  2. java动态分区分配_操作系统动态分区分配算法课程设计java版解析.doc

    湖 南 文 理 学 院 实 验 报 告 课程名称 操作系统课程设计 实验名称 存储管理--动态分区分配算法的模拟 成绩 学生姓名 曹乐 专业 计算机 班级.学号 13101 18 同组者姓名 实验日期 ...

  3. java动态分区分配算法,操作系统_动态分区分配算法课程设计_java版

    <操作系统_动态分区分配算法课程设计_java版>由会员分享,可在线阅读,更多相关<操作系统_动态分区分配算法课程设计_java版(13页珍藏版)>请在人人文库网上搜索. 1. ...

  4. java动态分区分配_操作系统 动态分区分配算法课程设计 java版.pdf

    操作系统 动态分区分配算法课程设计 java版 湖 南 文 理 学 院 实 验 报 告 课程名称 操作系统课程设计 实验名称 存储管理--动态分区分配算法的模拟 成绩 学生姓名 曹乐 专业 计算机 班 ...

  5. JS实现动态分区分配中的首次适应算法和最佳适应算法

    实验目的 了解动态分区分配方式中使用的数据结构和分配算法,并进一步加深对动态分区存储管理方式及其实现过程的理解. 实验内容 (1) 用C语言(不会C这里就用JS实现)分别实现采用首次适应算法和最佳适应 ...

  6. 操作系统之动态分区分配与回收—C语言实现

    前言 这篇文章用来记录操作系统实验之 动态分区分配与回收. 不想从网上copy代码,打算自己从头到尾写一下,没想到却花了我整整两个晚上的时间,好在终于写完了- 动态分区分配采用的算法是最佳适应(bes ...

  7. 操作系统分区分配java算法_合肥工业大学操作系统课程设计 动态分区分配存储管理java版.doc...

    合肥工业大学操作系统课程设计 动态分区分配存储管理java版.doc 1课程设计动态分区分配存储管理设计题目学号专业班级学生姓名号指导教师22010年12月合肥工业大学课程设计任务书设计题目动态分区分 ...

  8. 操作系统(三十六)动态分区分配算法

    3.5 动态分区分配算法 上节讲述了连续分区分配方式中有动态分区分配的方式,如果在动态分区分配算法中有许多空闲分区都满足需求的时候,那该如何分配空间呢,今天来介绍四种分配方法解决这个问题. 目录 3. ...

  9. 七、操作系统——动态分区分配算法(详解)

    一.引入 动态分区分配算法:在动态分区分配方式中,当很多个空闲分区都能满足需求时,应该选择哪个分区进行分配? 二.首次适应算法(First Fit) 算法思想:每次都从低地址开始查找,找到第一个能满足 ...

最新文章

  1. 人工智能/云原生/数据科学/计算等方向内容整理志愿者招募了!
  2. 如何在Linux系统上部署接口测试环境
  3. 802.11 MESH WLANs
  4. centos6.5下的elk部署
  5. BlueMind 3.0.17 发布,消息和协作平台
  6. Silverlight 2 RTW中ToolTipService.ToolTip不继承父节点的DataContext的问题
  7. 三图解决phpStorm部署ftp
  8. ES6结构赋值的用途
  9. 2015-2016 XVI Open Cup, Grand Prix of Bashkortostan, SKB Kontur Cup Stage 2
  10. java post上传进度,OkHttp实现文件上传进度
  11. Jquery和JS获取ul中li标签
  12. 贪心算法实例java,算法java实现--贪心算法--哈弗曼编码
  13. 各品牌路由器默认账号密码
  14. 中兴上网卡 linux,4G网卡中兴MF831移植到linux
  15. html开网站弹窗代码大全,JS弹出窗口代码大全(详细整理)
  16. [转]供应链管理方面的书籍
  17. 安卓 IOS上架流程
  18. 分词统计(四)唐宋元诗人吟诗作词的时候,最偏爱哪些词语呢?(附上AI写的1000句诗!)
  19. 223_动态设置页面指示器indicators
  20. 种群遗传学的多态性衡量参数

热门文章

  1. Spring Boot 2.0 新特性和发展方向
  2. 使用Nomad构建弹性基础架构:计划和自我修复
  3. Statement和PraparedStatement区别
  4. Java 分割字符串的方法String.split()底层原理
  5. 蓝桥杯比赛常考算法_备战蓝桥--算法竞赛入门第一章总结
  6. 综合布线的12大热点技术
  7. 综合布线五大技巧与综合布线规范详解
  8. 特定于数据中心的人工智能完成任务的速度可以提高两倍
  9. azure mysql 配置,微软Azure云MySQL in-app 的配置,简化PHP内容管理系统配置
  10. Python之pandas:pandas.set_option函数的参数详细解释