1. 设计合适的展示方式展示当前内存区的使用情况、空闲情况。
2. 模拟动态分区的分配过程,课本介绍的4种分配算法都需要实现(4.2.2小节下的第3点),直观的展示分配前后的情况。
3. 模拟动态分区的回收过程,根据设计使用的数据结构进行分区的前/后/前后合并,,直观的展示回收前后的情况。
#include<iostream>
#include<vector>
#include<cstring>
#include<string>
#include<cstdio>
#include<queue>
#include<map>
using namespace std;
map<bool, string >mp;
#define busy false
#define free true
//#define NotEnd 1
#define End INT_MAX
#define notEnd INT_MIN
struct zone{
int size; //分区大小
int start; //分区起始地址
bool status;//分区状态
};
struct process{
int id;//进程号
int start; /*进程在内存中的起始地址*/
process(){
start = -1;/*没调入内存的进程起始地址初始化为-1*/
}
int size;//进程大小
int runTime;//进程运行时间
};
vector<zone>freeTable; //分区表
queue<process>processQueue; //进程队列
vector<process>runVector; //在内存中运行的进程
bool cmpByAddress(zone z1, zone z2){/*按起始地址排序*/
return z1.start < z2.start;
}
bool cmpBySmallSize(zone z1, zone z2){/*小区在前, 大区在后排列*/
return z1.size < z2.size;
}
bool cmpByBigSize(zone z1, zone z2){/*大区在前, 小区灾后*/
return z1.size > z2.size;
}
void initProcess(){/*初始化进程*/
int n ;
cout<<"输入进程个数"<<endl;
cin>> n;
for(int i = 0; i < n; i++){
process ps;
cout<<"输入进程的id 大小 和 运行时间"<<endl;
cin>>ps.id;
//cout<<"输入进程的大小"<<endl;
cin>>ps.size;
//cout<<"输入进程的运行时间"<<endl;
cin>>ps.runTime;
processQueue.push(ps);
}
return ;
}
void initMemory(){/*初始化内存分配表*/
cout<<"输入初始内存的起始地址, 分区的大小 "<<endl;
zone ft;
cin>>ft.start;
cin>>ft.size;
//ft.id = code++;
ft.status = free;
freeTable.push_back(ft);
cout<<"初始化完成"<<endl;
return ;
}
void showMemory(){/*显示内存分配表*/
/*将内存按照起始地址从小到大的顺序排列*/
sort(freeTable.begin(), freeTable.end(),cmpByAddress);
int length = freeTable.size();
printf("%-8s %-8s %-8s %-8s\n", "分区号",
"分区大小/KB", "分区起始地址/K", "状态");//数据左对齐输出
//cout<<"length : "<<length<<endl;
for(int i = 0; i < length; i++){
//cout<<freeTable[i].id<<'\t'<<freeTable[i].size<<'\t'<<freeTable[i].start<<'\t'<<freeTable[i].status<<endl;
printf("%-8d %-8d %-8d %-8s\n",i + 1,
freeTable[i].size, freeTable[i].start, mp[freeTable[i].status].c_str());
}
return ;
}
void releaseProcess(){/*释放进程*/
while(true){
bool flag = false;
for(int i = 0; i < runVector.size(); ){
runVector[i].runTime--;//进程运行1个单位时间
if(runVector[i].runTime == 0){
//cout<<"进程"<<runVector[i].id<<"在内存中的起始地址是运行结束,释放内存了"<<endl;
printf("进程%d 在内存的起始地址是 %dK,大小是%d KB,其现在释放内存了\n",
runVector[i].id, runVector[i].start, runVector[i].size);
flag = true;
/*修改分配表*/
int lengthTable = freeTable.size();
for(int j = 0; j < lengthTable; j++){
//根据start 和 size 找到其在分配表的位置
if(freeTable[j].start == runVector[i].start && freeTable[j].size == runVector[i].size){
freeTable[j].status = free;/*修改为空闲状态*/
break;
}
}
/*将其从内存中删除,注意不能先修改分配表前删除该项*/
vector<process>::iterator it = runVector.begin() + i;
it = runVector.erase(it);/*记得要返回值*/
//i无须变化,为了让这一趟的进程都做到单位时间减少1
//break;
}
else
i++;
}
if(flag )/*这一趟有1个或多个进程释放了内存,不妨结束释放内存*/
break;
}
return ;
}
/*合并空闲区*/
int mergeMemory(){
/*合并内存之前要按地址从小到大排序*/
sort(freeTable.begin(), freeTable.end(), cmpByAddress);
bool FLAG = false;
for(int i = 0; i < freeTable.size(); i++){
if(freeTable[i].status == busy)
continue ;
bool flag = false;
int pre = i;
int step = pre + 1;
/*查找i下面的空闲的分区*/
while( (step < freeTable.size()) && (freeTable[pre].start + freeTable[pre].size == freeTable[step].start) && freeTable[step].status == free){
flag = true;
FLAG = true;
step++;/*step 和 pre 向后移动判断下一个空闲分区*/
pre++;
}
for(int k = i + 1; k <= step -1; k++){/*把 i + 1 到 step - 1 的分区合并到i分区中*/
freeTable[i].size += freeTable[k].size;
}
/*由于合并, 把 i + 1 到 step - 1这些分区合并了,在空闲表删除这些项*/
vector<zone>::iterator it = freeTable.begin() + i + 1;
for(int j =1; j <= step -1 -i ; j++){/*总共是删除step - 1-i项目*/
it = freeTable.erase(it);
}
if(flag)
i = -1;/*重新从头开始查找合并区间*/
}
if(FLAG)
return 1; /*有区间合并了*/
return 0; /*没有区间可合并*/
}
int allocateMemory(){/*除了循环适应其他都是调用这个分配内存*/
/*开始分配内存*/
process tmp;
if(processQueue.size() != 0){
int length = freeTable.size();//分配表大小
tmp = processQueue.front();//获取一个进程
int i;
//cout<<"start: "<<start<<endl;
for( i = 0 ; i < length; i++){
if(freeTable[i].size < tmp.size)//分区太小
continue;
//分区是空闲的且刚好足够容纳进程
if(freeTable[i].status == free && freeTable[i].size == tmp.size){
//cout<<"进程"<<tmp.id<<" 内存分配成功,其大小是 "<<tmp.size<<endl;
processQueue.pop();/*进程分配内存成功, 弹出进程队列*/
freeTable[i].status = busy;//修改分区状态
tmp.start = freeTable[i].start;//设置进程在内存的起始地址
runVector.push_back(tmp);/*调入内存*/
printf("进程%d内存分配成功,其在内存的起始地址是%d,大小是%d \n",
tmp.id, tmp.start, tmp.size);
break; //分配成功,不用继续查找分配表了
}
if(freeTable[i].status == free && freeTable[i].size > tmp.size){
int orginalSize = freeTable[i].size;//暂时保留原来的分区大小
freeTable[i].size = tmp.size;/*划分一区域为使用且把其标记为已使用*/
freeTable[i].status = busy;//标记为使用了
zone rest;/*分配给进程之后剩余内存*/
rest. size = orginalSize - tmp.size; //剩余大小
rest.start = freeTable[i].start + tmp.size;//剩余空闲分区起始地址
rest.status = free;//设置为
freeTable.push_back(rest);/*剩余空间加入分配表*/
//cout<<"进程"<<tmp.id<<"内存分配成功,其大小是 "<<tmp.size<<endl;
processQueue.pop();/*进程分配内存成功, 弹出进程队列*/
tmp.start = freeTable[i].start;//设置进程运行的起始地址
runVector.push_back(tmp);/*调入内存运行*/
printf("进程%d内存分配成功,其在内存的起始地址是%d,大小是%d \n",
tmp.id, tmp.start, tmp.size);
break ;
//return i;
}
}
if(i == length){//无足够大小的空闲区分配给进程
cout<<"当前无法分配足够的内存给进程"<<tmp.id;
cout<<" 等待某个进程释放"<<endl;
/*开始释放进程*/
releaseProcess();
/*释放进程之后整理分配表,使其地址从小到大排序,为了合并内存*/
//sort(freeTable.begin(), freeTable.end(), cmpByAddress);
/*然后合并内存*/
if(mergeMemory()){
cout<<"有相邻内存合并成功"<<endl;
}
}
cout<<"当前内存使用状况如下: "<<endl;
showMemory();
cout<<"---------------------------------------"<<endl;
/*if(i >= length)
return 0;
else
return i; */
return notEnd; /*表示此次有进程调入内存成功,进程队列不是空的*/
}
return End; /*表示全部的进程已成功分配内存*/
}
void reset(){/*重置相关数据结构*/
runVector.clear();/*清空在运行中的进程向量*/
runVector.shrink_to_fit();/*释放向量的内存*/
freeTable.clear();/*清空分配表*/
freeTable.shrink_to_fit();/*释放分配表的内存*/
queue<process>empty;
swap(empty, processQueue);/*清空进程队列*/
}
void Firstfit(){/*最先适应算法*/
initProcess();
initMemory();
cout<<"当前内存使用状况如下: "<<endl;
showMemory();
/*开始分配内存*/
int flag = 1;
while(flag != End){/*如果还有进程没调入内存*/
//先按起始地址从小到大排序,然后分配内存
sort(freeTable.begin(), freeTable.end(), cmpByAddress);
flag = allocateMemory();
}
}
void Bestfit(){/*最佳适应算法*/
initProcess();
initMemory();
cout<<"当前内存使用状况如下: "<<endl;
showMemory();
/*开始分配内存*/
int flag = 1;
while(flag != End){//进程队列还有进程,即还有进程没有调入内存
/*排序使得空闲区的小区在前,大区在后*/
sort(freeTable.begin(), freeTable.end(), cmpBySmallSize);
flag = allocateMemory();
}
}
void Nextfit(){/*循环适应算法*/
initProcess();
initMemory();
cout<<"当前内存使用状况如下: "<<endl;
showMemory();
/*开始分配内存*/
int last = -1;
process tmp;
while(processQueue.size() != 0){
bool flag = false; //标记这一趟是否成功分配内存给进程
int length = freeTable.size();//分配表大小
tmp = processQueue.front();//获取一个进程
int i ;
for( i = (last + 1)%freeTable.size() ; (i % freeTable.size() ) != last; i = (i + 1) % freeTable.size()){
if(freeTable[i].size < tmp.size)//分区太小
continue;
//分区是空闲的且刚好足够容纳进程
if(freeTable[i].status == free && freeTable[i].size == tmp.size){
flag = true;
cout<<"进程"<<tmp.id<<" 内存分配成功,其大小是 "<<tmp.size<<endl;
processQueue.pop();/*进程分配内存成功, 弹出进程队列*/
freeTable[i].status = busy;//修改分区状态
tmp.start = freeTable[i].start;//设置进程在内存的起始地址
runVector.push_back(tmp);/*调入内存*/
printf("进程%d内存分配成功,其在内存的起始地址是%d,大小是%d \n",
tmp.id, tmp.start, tmp.size);
break; //分配成功,不用继续查找分配表了
}
if(freeTable[i].status == free && freeTable[i].size > tmp.size){
flag = true;
int orginalSize = freeTable[i].size;//暂时保留原来的分区大小
freeTable[i].size = tmp.size;/*划分一区域为使用且把其标记为已使用*/
freeTable[i].status = busy;//标记为使用了
zone rest;/*分配给进程之后剩余内存*/
rest. size = orginalSize - tmp.size; //剩余大小
rest.start = freeTable[i].start + tmp.size;//剩余空闲分区起始地址
rest.status = free;//设置为
freeTable.push_back(rest);/*剩余空间加入分配表*/
//cout<<"进程"<<tmp.id<<"内存分配成功,其大小是 "<<tmp.size<<endl;
processQueue.pop();/*进程分配内存成功, 弹出进程队列*/
tmp.start = freeTable[i].start;//设置进程运行的起始地址
runVector.push_back(tmp);/*调入内存运行*/
printf("进程%d内存分配成功,其在内存的起始地址是%d,大小是%d \n",
tmp.id, tmp.start, tmp.size);
break ;
}
}
if( i == last){//无足够大小的空闲区分配给进程
cout<<"当前无法分配足够的内存给进程"<<tmp.id;
cout<<" 等待某个进程释放"<<endl;
/*开始释放进程*/
releaseProcess();
/*释放进程之后整理分配表,使其地址从小到大排序,为了合并内存*/
sort(freeTable.begin(), freeTable.end(), cmpByAddress);
/*然后合并内存*/
if(mergeMemory()){
cout<<"有相邻内存合并成功"<<endl;
}
}
if(flag )/*成功分配内存,更新上一次分配内存的位置*/
last = i;
//cout<<"last: "<<last<<endl;
cout<<"当前内存使用状况如下: "<<endl;
showMemory();
cout<<"---------------------------------------"<<endl;
}
}
void Worstfit(){/*最坏适应算法*/
initProcess();
initMemory();
cout<<"当前内存使用状况如下: "<<endl;
showMemory();
/*开始分配内存*/
int flag = 1;
while(flag != End){//进程队列还没分配完
/*排序使得空闲区的大区在前*/
sort(freeTable.begin(), freeTable.end(), cmpByBigSize);
flag = allocateMemory();
}
}
int main()
{
mp[busy] = "busy";
mp[free] = "free";
cout<<"---------------------最先适应算法---------------------"<<endl;
Firstfit();
reset();
cout<<"---------------------最佳适应算法----------------"<<endl;
Bestfit();
reset();
cout<<"---------------------循环适应算法--------"<<endl;
Nextfit();
reset();
cout<<"---------------------最坏适应算法--------"<<endl;
Worstfit();
system("pause");
}
测试数据:
最先适应算法测试数据
进程个数及其具体信息(进程id ,大小,运行时间 )
5
1 10 3
2 5 3
3 15 9
4 10 3
5 5 7
内存起始地址和大小
0 40
最佳适应算法测试数据
进程个数及其具体信息(进程id ,大小,运行时间 )
5
1 10 3
2 10 3
3 15 7
4 5 3
5 5 7
内存起始地址和大小
0 40
循环适应算法测试数据
进程个数及其具体信息(进程id ,大小,运行时间 )
6
1 10 5
2 10 2
3 10 2
4 10 5
5 20 10
6 10 7
内存的起始地址和大小
0 40
最坏适应算法测试数据
进程个数及其具体信息(进程id ,大小,运行时间 )
5
1 10 3
2 5 9
3 15 3
4 15 3
5 10 1
内存起始地址和大小
0 45