Operating system experiment - main memory allocation and release (C language)

Table of contents

Experimental requirements

Code

operation result

Code analysis


Experimental requirements

1. Simulate the main memory allocation of the operating system, and use the storage management algorithm of variable partitions to design the main memory allocation and recycling program without actually starting the loading operation.

2. Adopt the first to adapt method.

3. When a new job requires loading into the main memory, the free area table must be checked to find a large enough free area. If the free area found is larger than the job requirement, it should be divided into two parts, one part is the occupied area, and the other part becomes a free area.

4. When a job is evacuated, if the returned area is adjacent to other free areas, it should be merged into a larger free area and listed in the free area table.

5. Run the designed program and output the changes in the data structure table items and the current status of the memory. 

Code

#include <stdio.h>
#define CAP 1024    //初始化内存容量 
#define SYSCAP 100  //系统所占地址,从低位开始 
#define N 1000		//进程最大个数 

//作业分区 
struct USED{
	int id,sp,ep,longsize;
}a[N];

//空闲分区 
struct FREE{
	int id,sp,ep,longsize;
}b[N];

//anum为作业分区块数,bnum为空闲分区块数。初始时作业分区0块,空闲分区有1块
int anum=0,bnum=1;        
void Init()              //初始化函数,程序开始时只有一个空闲分区 
{
	b[0].id=0;b[0].sp=SYSCAP;b[0].ep=CAP;b[0].longsize=b[0].ep-b[0].sp;
	printf("\n\n--------------最先适应算法--------------\n"); 
	printf("\n内存总量为:%dk\n",CAP); 
	printf("系统占用容量为:%dk\n",SYSCAP);
	printf("---------------------------------------------\n"); 
	printf("空闲分区    起始地址    结束地址    长度\n");
	printf("   %d          %d         %d       %d\n",b[0].id,b[0].sp,b[0].ep,b[0].longsize);
	printf("---------------------------------------------\n"); 
}
void Print(int anum,int bnum)      //格式化输出作业分区和空闲分区表 
{
	int i,j;
	printf("-----------------作业分区表---------------------\n"); 
	printf("作业分区    起始地址    结束地址    长度\n");
	for(i=0;i<anum;i++)
	{
		printf("   %d          %d         %d         %d\n",a[i].id,a[i].sp,a[i].ep,a[i].longsize);
	}
	printf("------------------空闲分区表--------------------\n"); 
	printf("空闲分区    起始地址    结束地址    长度\n");
	for(i=0;i<bnum;i++)
	{
		printf("   %d          %d         %d        %d\n",i,b[i].sp,b[i].ep,b[i].longsize);
	} 
	printf("---------------------------------------------\n\n\n"); 
}
void Put()                   //进程装入作业 
{
	int size;
	printf("请输入作业%d的大小\n",anum);
	scanf("%d",&size);
	int i;
	for(i=0;i<bnum;i++)
	{
		b[i].longsize=b[i].ep-b[i].sp;       //更新各空闲分区长度 
		if(b[i].longsize>=size)     //找到第一个能放下进程的空闲分区 
		{
			a[anum].id=anum;			//空闲区id 
			a[anum].sp=b[i].sp;			//作业内存起始地址等于空闲分区起始地址 
			a[anum].ep=a[anum].sp+size; //作业的结束地址等于起始地址+作业长度 
			b[i].sp=b[i].sp+size;		//空闲分区起始地址应向后移动size 
			a[anum].longsize=size;		//更新作业地址长度到结构体数组中 
			b[i].longsize=b[i].ep-b[i].sp;//更新空闲分区地址长度 
			anum++;						//作业数+1 
			break;						//一次只放入一个作业,结束查找 
		}
	}
	Print(anum,bnum);                   //打印结果 
}

void Merge()	//合并空闲分区,查找结束地址和开始地址重合的地址进行合并 
{
	int i,j;
	if(bnum>=1)   //当空闲分区大于等于两个时,才需要检查是否存在可合并的区间 
	{
		for(i=0;i<bnum-1;i++)//从第一个开始检查,到倒数第二个停止 
		{
			if(b[i].ep==b[i+1].sp)
			{
				bnum--;     //存在可合并区间,合并后空闲区间-1 
				b[i].ep=b[i+1].ep;  //结束地址变为合并后的结束地址 
				b[i].longsize=b[i].ep-b[i].sp;//更新空闲区间长度 
				for(j=i+1;i<bnum;i++)
				{
					b[j]=b[j+1];  //删除第i+1个空闲区间 
				}
			}
		}
	}
	
}

void Sort(int anum,int bnum)//简单排序函数,将空闲区间按起始地址递增的顺序排序 
{
	int i,j,min;
	for(i=0;i<bnum;i++)
	{
		min=b[i].sp;
		for(j=i;j<bnum;j++)
		{
			if(b[j].sp<min)
			{
				min=b[j].sp;
				b[N-1]=b[j];
				b[j]=b[i];
				b[i]=b[N-1];
			}
		}
	}
}

void Remove()//回收作业 
{
	int i,j,flag=1;//flag是标志位 
	printf("请输入需要回收的作业:\n");
	scanf("%d",&i);
	//回收作业存在下面两种情况 
	
	for(j=0;j<bnum;j++)//情况1:回收作业后,被回收作业地址刚好能和已存在的空闲分区合并,不需要增加空闲分区块数 
	{
		if(a[i].ep==b[j].sp)
		{
			b[j].sp=a[i].sp;   
			b[j].longsize=b[j].ep-b[j].sp;
			flag=0;  //标志位置0,只能执行一种情况 
			break;
		}
	}
	if(flag)		//情况2:回收作业后,被回收地址不能与已存在的空闲区间合并,需要增加空闲分区块数 
	{				//创建新的空闲分区 
		
		b[bnum].sp=a[i].sp;
		b[bnum].ep=a[i].ep;
		b[bnum].longsize=a[i].longsize;
		b[bnum].id=bnum;
		bnum++;		//空闲分区个数+1 
	}
	anum--;         //移除作业后,作业数-1 
	for(;i<anum;i++)
	{
		a[i]=a[i+1];//删除第i个作业分区 
		a[i].id--; //作业id对应-1 
	}
	Sort(anum,bnum);//排序 
	Merge();//再次检查合并空闲分区,防止出现增加空闲分区后出现的可合并分区 
	Print(anum,bnum);//打印结果 
}
int main()
{
	int input;//input 代表程序运行状态
	Init();//初始化,输出 
	while(1)//写一个死循环 
	{
		printf("装入作业:1  回收作业:0  其他输入结束程序\n");
		scanf("%d",&input);
		if(input==1)
		{
			Put();
		}else if(input==0)
		{
			Remove();
		}else break;//任意数字退出循环,程序结束 
	}
	return 0;
}

operation result

 Code analysis

Define the total amount of memory and system memory as macros (if necessary, just modify the data of the macro definition directly)

Define two structure arrays, respectively used to store and free partition status data

anum and bnum are global variables, representing the number of job partitions and free partitions respectively. 

#include <stdio.h>
#define CAP 1024    //初始化内存容量 
#define SYSCAP 100  //系统所占地址,从低位开始 
#define N 1000		//进程最大个数 
//作业分区 
struct USED{
	int id,sp,ep,longsize;
}a[N];
//空闲分区 
struct FREE{
	int id,sp,ep,longsize;
}b[N];
int anum=0,bnum=1;

  

 Initialization function prints initial data before the algorithm program starts processing. Here the array subscript starts from 0

void Init()              //初始化函数,程序开始时只有一个空闲分区 
{
	b[0].id=0;b[0].sp=SYSCAP;b[0].ep=CAP;b[0].longsize=b[0].ep-b[0].sp;
	printf("\n\n--------------最先适应算法--------------\n"); 
	printf("\n内存总量为:%dk\n",CAP); 
	printf("系统占用容量为:%dk\n",SYSCAP);
	printf("---------------------------------------------\n"); 
	printf("空闲分区    起始地址    结束地址    长度\n");
	printf("   %d          %d         %d       %d\n",b[0].id,b[0].sp,b[0].ep,b[0].longsize);
	printf("---------------------------------------------\n"); 
}

Print the results and print the corresponding structure data in order.

void Print(int anum,int bnum)      //格式化输出作业分区和空闲分区表 
{
	int i,j;
	printf("-----------------作业分区表---------------------\n"); 
	printf("作业分区    起始地址    结束地址    长度\n");
	for(i=0;i<anum;i++)
	{
		printf("   %d          %d         %d         %d\n",a[i].id,a[i].sp,a[i].ep,a[i].longsize);
	}
	printf("------------------空闲分区表--------------------\n"); 
	printf("空闲分区    起始地址    结束地址    长度\n");
	for(i=0;i<bnum;i++)
	{
		printf("   %d          %d         %d        %d\n",i,b[i].sp,b[i].ep,b[i].longsize);
	} 
	printf("---------------------------------------------\n\n\n"); 
}

 Core algorithm: load the job into the memory (the specific implementation methods are all written in the comments, if you still don’t understand, you can send me a private message)

void Put()                   //进程装入作业 
{
	int size;
	printf("请输入作业%d的大小\n",anum);
	scanf("%d",&size);
	int i;
	for(i=0;i<bnum;i++)
	{
		b[i].longsize=b[i].ep-b[i].sp;       //更新各空闲分区长度 
		if(b[i].longsize>=size)     //找到第一个能放下进程的空闲分区 
		{
			a[anum].id=anum;			//空闲区id 
			a[anum].sp=b[i].sp;			//作业内存起始地址等于空闲分区起始地址 
			a[anum].ep=a[anum].sp+size; //作业的结束地址等于起始地址+作业长度 
			b[i].sp=b[i].sp+size;		//空闲分区起始地址应向后移动size 
			a[anum].longsize=size;		//更新作业地址长度到结构体数组中 
			b[i].longsize=b[i].ep-b[i].sp;//更新空闲分区地址长度 
			anum++;						//作业数+1 
			break;						//一次只放入一个作业,结束查找 
		}
	}
	Print(anum,bnum);                   //打印结果 
}

 Core algorithm: Recycle the job and recycle the memory occupied by the job into a free area

 Let’s talk about why there are two situations when recycling operations written in the code

Case 1:

During job recycling, entering the free partition can be directly merged with the free partition without adding a new free partition (as shown below)

 After recycling and merging:

Case 2:

During job recycling, when entering the free partition, it cannot be directly merged with the free partition, and a new free partition needs to be added (as shown in the figure below, the yellow block is the job partition to be recycled)

After recycling and merging:

void Remove()//回收作业 
{
	int i,j,flag=1;//flag是标志位 
	printf("请输入需要回收的作业:\n");
	scanf("%d",&i);
	//回收作业存在下面两种情况 
	
	for(j=0;j<bnum;j++)//情况1:回收作业后,被回收作业地址刚好能和已存在的空闲分区合并,不需要增加空闲分区块数 
	{
		if(a[i].ep==b[j].sp)
		{
			b[j].sp=a[i].sp;   
			b[j].longsize=b[j].ep-b[j].sp;
			flag=0;  //标志位置0,只能执行一种情况 
			break;
		}
	}
	if(flag)		//情况2:回收作业后,被回收地址不能与已存在的空闲区间合并,需要增加空闲分区块数 
	{				//创建新的空闲分区 
		
		b[bnum].sp=a[i].sp;
		b[bnum].ep=a[i].ep;
		b[bnum].longsize=a[i].longsize;
		b[bnum].id=bnum;
		bnum++;		//空闲分区个数+1 
	}
	anum--;         //移除作业后,作业数-1 
	for(;i<anum;i++)
	{
		a[i]=a[i+1];//删除第i个作业分区 
		a[i].id--; //作业id对应-1 
	}
	Sort(anum,bnum);//排序 
	Merge();		//再次检查合并空闲分区,防止出现增加空闲分区后出现的可合并分区 
	Print(anum,bnum);//打印结果 
}

Sorting algorithm, re-sorting addresses from large to small after each recycling (this step is required)

Job recycling is arbitrary. If the high address blocks are recycled first without sorting, the high addresses will be allocated first when the free partition is retrieved next time. Obviously, this does not comply with the definition of the best adaptation algorithm.

void Sort(int anum,int bnum)//简单排序函数,将空闲区间按起始地址递增的顺序排序 
{
	int i,j,min;
	for(i=0;i<bnum;i++)
	{
		min=b[i].sp;
		for(j=i;j<bnum;j++)
		{
			if(b[j].sp<min)
			{
				min=b[j].sp;
				b[N-1]=b[j];
				b[j]=b[i];
				b[i]=b[N-1];
			}
		}
	}
}

 Merge function, check and then merge. This is actually the third situation that occurs after processing the previous two situations.

 

After recycling and merging: 

void Merge()	//合并空闲分区,查找结束地址和开始地址重合的地址进行合并 
{
	int i,j;
	if(bnum>=1)   //当空闲分区大于等于两个时,才需要检查是否存在可合并的区间 
	{
		for(i=0;i<bnum-1;i++)//从第一个开始检查,到倒数第二个停止 
		{
			if(b[i].ep==b[i+1].sp)
			{
				bnum--;     //存在可合并区间,合并后空闲区间-1 
				b[i].ep=b[i+1].ep;  //结束地址变为合并后的结束地址 
				b[i].longsize=b[i].ep-b[i].sp;//更新空闲区间长度 
				for(j=i+1;i<bnum;i++)
				{
					b[j]=b[j+1];  //删除第i+1个空闲区间 
				}
			}
		}
	}
	
}

main function. Call the corresponding processing function through user input

int main()
{
	int input;//input 代表程序运行状态
	Init();//初始化,输出 
	while(1)//写一个死循环 
	{
		printf("装入作业:1  回收作业:0  其他输入结束程序\n");
		scanf("%d",&input);
		if(input==1)
		{
			Put();
		}else if(input==0)
		{
			Remove();
		}else break;//任意数字退出循环,程序结束 
	}
	return 0;
}

Thanks for reading~ If you have any good suggestions, you can comment or send me a private message~ If you don’t understand something, you can also send me a private message~

If you find it useful, please give it a like and leave~

Guess you like

Origin blog.csdn.net/Lic_Ac/article/details/128021354