**
web
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;"><path stroke-linecap="round" d="M5,0 0,2.5 5,5z" id="raphael-marker-block" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></path></svg> <h2><a id="_0" target="_blank"></a>内存管理</h2>
设计程序模拟内存的动态分区内存管理方法。内存空闲区使用空闲分区表进行管理,采用最早适应算法从空闲分区表中寻找空闲区进行分配,内存回收时不考虑与相邻空闲区的合并。
假定系统的内存共640K,初始状态为操做系统自己占用40K。算法
t1 时刻,为做业A、B、C分配80K、60K、100K、的内存空间;
t2 时刻做业B完成;
t3 时刻为做业D分配50K的内存空间;
t4 时刻做业C、A完成;
t5 时刻做业D完成。编程
要求编程序分别输出t一、t二、t三、t四、t5时刻内存的空闲区的状态。markdown
流程图:
数据结构
数据结构定义:
//进程PCB类型的描述
struct PCB
{
char name; //进程名
int address; //进程分区起止
int len; //进程所占分区长度
};
struct PCB PCBelem[maxPCB];//进程占用内存表
//分区类型的描述
struct Part
{
int address; //空闲分区起始地址
int len; //空闲分区大小
};
struct Part Partelem[maxPart]; //空闲分区表svg
主要变量说明:
int length = 640 ; //系统有 640 KB 的空闲
int fnum = 0; //记录总的分区数量
int jnum = 0; //记录总的进程数量
int leng = 0; //临时变量函数
函数说明:
void init4IOS(int tem) //为操做系统分配40k内存
int getTagByPcb(char name) //断定输入的进程是否存在以及位置
void request() //进程分配请求
void getPrint() //打印空闲分区
void jcPrintf() //打印进程
void release() //回收指定进程内存优化
关键点叙述:atom
(1) 内存结构的创建及表示
分别创建进程占用内存表和空闲分区表,因为进程和空闲分区的全部属性值不同,因此须要分别建表,它们之间起始地址是连续的,逻辑上造成一整块内存。操作系统
(2) 进程请求分配
当进程提出内存分配请求之后,首先须要作的是在空闲分区表当中寻找一个单独的,足够请求进程分配的内存空间。注意,寻求该空间须要从内存低址开始寻找,这样有利于保护高址大块内存,固然,缺点就是会产生较多的碎片内存,这些内存难以被利用。(本程序未涉及相邻空闲空间的合并,以及内存空间的紧凑)若存在这样一个空间,则从该空间当中划出请求进程所需的内存大小,将该内存块(含有起始地址等信息的结构体结点)存入进程占用内存表当中,同时,对于被划分的内存空间,须要修改其起始地址,达到逻辑上的合理。值得一提的是,若内存分配之后,被划份内存空间大小为0,则须要除去该条记录(移除(覆盖)空闲分区表)。
(3)回收进程
当对指定进程提出回收要求时,会产生两个反应,一是会对空闲分区表插入一块内存,用以表示被回收内存的空闲已空闲出来;二是对于被回收的进程,不该该出如今进程占用表当中,因此应当将其移除进程占用表。
对于以上两个操做的实现:对空闲分区表插入空闲内存时,须要从高址内存空间开始对比插入内存空间的大小,当出现内存空间的起始地址小于插入内存空间的起始地址时中止对比查找,将其后的内存空间均向后移动一位,以腾出一个位置用于插入须要插入的空闲内存空间,这样在物理结构上也就合理了。除去被回收的进程,思想与上相似,找到该进程之后,将该进程之后的结点均向前移动一位,末尾指向相应减一,除去被回收的进程目的在于避免对同一进程进行重复回收。
存在问题:
模拟内存管理所实现效果简单,与真实内存分配存在很大差别。
改进:
(1) 实现相邻空闲空间的合并
(2) 内存空间紧凑
(3) 其余优化
我的总结:
一、 本程序编写完成之后,初步理解内存管理过程。程序实现的功能较为简单,没有考虑相邻空闲分区的合并,以及碎片空间的紧凑整理等操做。
二、越努力,越幸运!_
程序效果图(部分):
完整代码:
#include "stdio.h" #include "Windows.h" #define maxPCB 100 //定义最大PCB结点数 #define maxPart 100 //定义最大分区 //进程PCB类型的描述 struct PCB { char name; //进程名 int address; //进程分区起止 int len; //进程所占分区长度 }; struct PCB PCBelem[maxPCB];//进程占用内存表 //分区类型的描述 struct Part { int address; //空闲分区起始地址 int len; //空闲分区大小 }; struct Part Partelem[maxPart];//空闲分区表 int length = 640 ; //系统有 640 KB 的空闲 int fnum = 0; //记录总的分区数量 int jnum = 0; //记录总的进程数量 struct Part part; //公共使用临时结点(分区) struct PCB pcb; //公共使用临时结点(进程) //为操做系统分配40k内存 void init4IOS(int tem) { length = length - tem; //剩余系统空闲空间减小 part.address = 0 + 40; //操做系统占用,空闲内存从40开始 part.len = length; //空闲内存大小 Partelem[fnum] = part; //存入空闲分区表 fnum ++; //分区数增长 } //断定输入的进程是否存在以及位置 int getTagByPcb(char name) { int i; for(i = 0; i < jnum; i ++) { if(name == PCBelem[i].name) { return i; } } printf("\n\t\t找不到进程名%c,请从新输入!\n",name); return -1; } //进程分配请求 void request() { char c = 0; while(true) { printf("\n\t\t请输入请求内存进程 名称:"); fflush(stdin);//清空缓冲区 scanf("%c",&pcb.name); //检查是否已存在进程 for(int j = 0; j < jnum; j++) { if(PCBelem[j].name == pcb.name) { printf("\n\t\t进程 %c 已存在,可尝试输入其余名称,也能够先回收该进程!\n",pcb.name); return; } } printf("\n\t\t\t\t 长度:"); fflush(stdin);//清空缓冲区 scanf("%d",&pcb.len); length = length - pcb.len; //减去相对应的操做系统剩余空闲空间 if(length <= 0) { if(length == 0) { printf("\n\t\t警告:系统资源已经所有分配!\n"); } else { length = length + pcb.len; //分配失败将内存换回去,以避免溢出 printf("\n\t\t未找到合适空间或者系统资源不足!\n"); return; } } //若是符合分配条件,进行分配 for(int i = 0; i < fnum; i++) { //寻找一个能够分配的空间 if(pcb.len <= Partelem[i].len) { //改变进程占用地址 pcb.address = Partelem[i].address; //保存该进程 PCBelem[jnum++] = pcb; //对空闲分区进行划分 Partelem[i].address = Partelem[i].address + pcb.len; Partelem[i].len = Partelem[i].len - pcb.len; break;//关键做用(从低址找到一个空间就能够了,不必再日后找了) } } //除去分配后空闲空间为0的记录 if(Partelem[i].len == 0) { int leng = i; //进行前移覆盖 while(leng != fnum) { part.address = Partelem[leng+1].address; part.len = Partelem[leng+1].len; Partelem[leng] = part; leng++; } //分区数减小 fnum--; } printf("\n\t\t是否要继续输入进程?(Y/y) 是/(N/n) 否:"); fflush(stdin); c = getchar(); fflush(stdin); if(c=='N'||c=='n') { break; } } } //打印空闲分区 void getPrint() { printf("\t\t----------------------空闲分区 begin----------------------\n"); int j = 1; for (int i = 0;i < fnum; i ++) { printf("\n\t\t第%d块空闲内存 起始地址为%d,容量为%d\n",j,Partelem[i].address,Partelem[i].len); j ++; } printf("\n\t\t----------------------空闲分区 end ----------------------\n"); } //打印进程 void jcPrintf() { printf("\n\t\t名称\t起始地址\t大小\n"); for(int i = 0 ; i < jnum; i++) { printf("\n\t\t%2c\t%4d\t\t%d KB\n",PCBelem[i].name,PCBelem[i].address,PCBelem[i].len); } } //回收指定进程内存 void release() { int i = 0; char name; printf("\n\t\t请输入想要回收的进程名称:"); fflush(stdin);//清空缓冲区 scanf("%c",&name); if(getTagByPcb(name) == -1) { printf("\n\t\t该进程不存在或者已经被回收!\n"); return; } printf("\n\t\t正在回收%c的内存:",name); for(int j = 0; j < 15; j++) { printf("▊"); Sleep(200); } printf(" 完成 \n"); //for循环寻找该进程 for(i = fnum; i >= 0; i --) { int leng = fnum; if(PCBelem[getTagByPcb(name)].address > Partelem[i-1].address || i == 0) { //while循环为该进程腾出一个位置 while(leng != i) { part.address = Partelem[leng-1].address; part.len = Partelem[leng-1].len; Partelem[leng] = part; leng--; } break;//关键(从高址往前找到一个空间就能够了,不必再往前找了) } } //系统空闲空间对应增长 length = length + PCBelem[getTagByPcb(name)].len; //使用公共的结点记录即将产生的空闲空间 part.address = PCBelem[getTagByPcb(name)].address; part.len = PCBelem[getTagByPcb(name)].len; //将该结点存入以前腾出的位置 Partelem[i] = part; //分区数增长 fnum ++; //对进程占用内存表进行调整,除去被回收进程 int leng = getTagByPcb(name); //进行前移覆盖 while(leng != jnum) { pcb.name = PCBelem[leng+1].name; pcb.address = PCBelem[leng+1].address; pcb.len = PCBelem[leng+1].len; PCBelem[leng] = pcb; leng++; } //进程数减小 jnum--; } void main() { char tem = 0; int OSsize = 40; int b = 1, k; //为操做系统分配内存 init4IOS(OSsize); while (b) { system("cls"); printf("\n\n\t\t操做系统内存分配\n\n"); printf("\t\t已为操做系统分配了 40 KB 内存\n",tem); printf("\n\t\t ----------------------------\n"); printf("\t\t|1.... 请求分配内存 |\n"); printf("\t\t|2.... 输出空闲分区 |\n"); printf("\t\t|3.... 强制进程结束 |\n"); printf("\t\t|4.... 输出进程信息 |\n"); printf("\t\t|0.... 退出 |\n"); printf("\t\t ----------------------------\n\n"); printf("\t\t当前操做系统空闲内存:%d KB\n",length); printf("\n\t\t请选择:"); scanf("%d", &k); switch (k) { case 1: request(); break; case 2: getPrint(); break; case 3: release(); break; case 4: jcPrintf(); break; case 0: b = 0; break; } if (b != 0) { printf("\n\t\t"); system("pause"); } } }
若有错误,欢迎指正!