操作系统课程设计 存储管理——动态分区空闲空间分配算法的模拟

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

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值