操作系统——连续动态内存管理模拟实现

引子
连续动态内存管理,该实验其实就是对双向链表进行操作来模拟内存分配,比起普通链表更细心一点就行。

一、实验目的
1) 理解内存管理相关理论;
2) 掌握连续内存管理理论;
3) 掌握动态连续内存管理理论。

二、实验内容
本实验主要针对操作系统中内存管理相关理论进行实验,要求实验者编写一个程序,该程序管理一块虚拟内存,实现内存分配和回收功能。
1) 模拟管理 64M 的内存块;
2) 设计内存分配函数;
3) 设计内存回收函数;
4) 实现动态分配和回收操作;
5) 可动态显示每个内存块信息。

三、实验原理
连续内存分配:为一个用户程序分配一个连续的内存空间,它分为单一连续分配,固定分区分配和动态分区分配,在本实验中,我们主要讨论动态分区分配。
动态连续分配:根据进程的实际需要,动态地为之分配内存空间。在实现可变分区分配时,将涉及到分区分配中的所用的数据结构、分区分配算法和分区的分配与回收操作这几个问题。

  1. 分区分配中的数据结构
    (1) 空闲分区表:一张数据表,用于记录每个空闲块的情况,如起始地址、大小,使用情况等。
    (2) 空闲分区链:为了实现对空闲分区的分配,把所有的空闲内存块连成一个双向链,便于分配和回收。
  2. 分区分配算法
    (1) 首次适应算法:从链首出发,寻找满足申请要求的内存块。
    (2) 循环首次适应算法:从上次查找的下一个空闲块开始查找,直到找到满足要求的内存块。
    (3) 最佳适应算法:在每次查找时,总是要找到既能满足要求又最小的内存块给分配给用户进程。为了方便查找,所有的空闲内存块按从小到大的顺序存放在空闲链表中。
  3. 内存分配操作
    利用分配算法查找到满足要求的内存块,设请求内存大小为 u.size,而分配的内存块大小为 m.size,如果 m.size-u.size≤size (size 为设定的不可再分割的内存大小),则不再切割;反之,按 u.size 分配给申请者,剩余的部分仍留在内存链中。
  4. 回收内存
    根据回收区地址,从空闲链表中找到相应的插入点。
    (1) 回收区与插入点的前一个空闲分区相邻,此时将回收区与前一分区合并,不为回收区分配新表项。
    (2) 回收区与插入点的后一个空闲分区相邻,将回收区与后一分区合并成一个新区,回收区的首址最为新分区的首址。
    (3) 回收区与前(F1)后(F2)分区相邻,则把三个分区合并成一个大的分区,使 F1 的首址作为新分区的首址,修改 F1 大小,撤销 F2 表项。
    (4) 回收区不与任何分区相邻,为回收区建立一个新表项。

C++代码如下:

#include <cstdio>
#include <iostream> 

using namespace std;
struct Elem{
	int num;		//分区序号
	int begin;		//起始地址
	int size;		//分区大小
	int status;		//使用状态 
};

//空闲分区链的每一个结点,空闲分区链是一个双向链表 
struct Node
{		 
	Elem data;
	Node* prior;	//前趋指针 
	Node* next;		//后趋指针 
};

//空闲分区链 
class LinkedList
{
private:
	Node* first;	//头结点 
	Node* end; 		//尾结点 
	Node* record;	//记录上次查找的空闲块 
public:
	void InitLinkedList();
	void show();
	int first_fit(int request);
	int cycle_first_fit(int request); 	//写出来有bug,还是不贴出来了 
	int best_fit(int request);			//最佳适应算法 
	int recovery(int mnum);				//回收分区			
};

void LinkedList::InitLinkedList()
{
	first=new Node();
	end=new Node();
	first->prior=NULL;
	first->next=end;
	end->prior=first;
	end->next=NULL;
	end->data.num=1;
	end->data.begin=40;
	end->data.size=600;
	end->data.status=0;
	
	first->data.num=0;
	first->data.begin=0;
	first->data.size=40;
	first->data.status=1;
}

//首次适应算法 
int LinkedList::first_fit(int request)
{
	Node *p=first->next;
	while(p)
	{
		//有大小正好合适的内存块 
		if(p->data.status==0&&p->data.size==request)
		{
		 	p->data.status=1;				
		 	return 1;
		}
		//有空闲块且能满足需求,分块后有剩余 
		else if(p->data.status==0&&p->data.size>request)
		{
			Node* temp=new Node();
			temp->data.size=request;
			temp->data.status=1;
			
			temp->prior=p->prior;
			temp->next=p;
			temp->data.begin=p->data.begin;
			
			p->prior->next=temp;
			p->prior=temp;
			p->data.begin=temp->data.begin+request;
			p->data.size-=request;
			record=p;				//记录上次查找的下一个空闲块 
			
			//重新分配分区序号 
			Node* p2=first->next;
			int nums=1;
			while(p2)
			{
				p2->data.num=nums++;
				if(p2->next==NULL)
				{
					end=p2;			//重置尾结点 
				}
				p2=p2->next;
			}
			
			return 1;
		}
		
		//记录上次查找的下一个空闲块 
		else if(p->data.status==0)
		{
			record=p;
		}
		
		p=p->next;
	} 
	return 0;
}


int LinkedList::best_fit(int request)
{
	Node* p=first->next;
	Node* re=NULL;
	int rsize=0;
	
	//找到最小的满足需求的内存块 
	while(p)
	{
		//有大小正好合适的内存块 
		if(p->data.status==0&&p->data.size==request)
		{
			p->data.status=1;				
			return 1;
		}
		//有空闲块且能满足需求,则记录最小的满足需求的空闲内存块 
		else if(p->data.status==0&&p->data.size>request)
		{
			if(re==NULL)
			{
				re=p;
				rsize=p->data.size;
			}
			else if(rsize>p->data.size)
			{
				re=p;
				rsize=p->data.size;
			}
		}
		p=p->next;
	}
	
	//能找到最小的空闲块 
	if(re!=NULL)
	{
		Node* temp=new Node();
		temp->data.size=request;
		temp->data.status=1;
					
		temp->prior=re->prior;
		temp->next=re;
		temp->data.begin=re->data.begin;
					
		re->prior->next=temp;
		re->prior=temp;
		re->data.begin=temp->data.begin+request;
		re->data.size-=request;
		
		//重新分配分区序号 
		Node* p2=first->next;
		int nums=1;
		while(p2)
		{
			p2->data.num=nums++;
			if(p2->next==NULL)
			{
				end=p2;			//重置尾结点 
			}
			p2=p2->next;
		}
		
		return 1;
	}
	
	return 0;
}

int LinkedList::recovery(int mnum)		//回收被占用的分区 
{
	//最好别删除头结点,因为链表结构没有设置得很好,本来应该在头部加一个头结点的 
	if(mnum==0)
	{
		return 0;
	} 
	Node* p=first;
	while(p!=NULL&&p->data.num!=mnum)
	{
		p=p->next;						//找到该序号对应的分区 
	}	
	//没有找到该分区 
	if(p==NULL)
	{
		return 0;
	}
	//找到该分区相邻的空闲分区
	Node* pre=p;Node* rear=p;
	int size=p->data.size; 				//记录总空闲区间的内存大小 
	while(pre->prior!=NULL&&pre->prior->data.status==0)
	{
		pre=pre->prior;
		size+=pre->data.size;
	}
	while(rear->next!=NULL&&rear->next->data.status==0)
	{
		rear=rear->next;
		size+=rear->data.size;
	}
	
	//回收之后形成的新的空闲分区 
	Node *temp=new Node();
	temp->data.size=size;
	temp->data.begin=pre->prior->data.begin+pre->prior->data.size;
	temp->data.status=0;
	
	//连接上总表 
	temp->next=rear->next;
	temp->prior=pre->prior;
	
	pre->prior->next=temp;
	if(rear->next!=NULL) rear->next->prior=temp;
	
	//删除旧结点 
	p=pre;
	while(p!=rear)
	{
		p=p->next;
		delete p->prior;
	}
	delete p;
	
	//重置分区号 
	Node* p2=first->next;
	int nums=1;
	while(p2)
	{
		p2->data.num=nums++;
		if(p2->next==NULL)
		{
			end=p2;			//重置尾结点 
		}
		p2=p2->next;
	}
	return 1;
}




void LinkedList::show()
{
	Node* p=first;
	printf("\n\t\t》主存空间分配情况《\n");      
    printf("**********************************************************\n\n");     
    printf("分区序号\t起始地址\t分区大小\t分区状态\n\n");     
    while(p)     
    {        
        printf("%d\t\t%d\t\t%d",p->data.num,p->data.begin,p->data.size);         
        if(p->data.status==0) printf("\t\t空闲\n\n");         
        else printf("\t\t已分配\n\n"); 
        p=p->next;      
    }      
    printf("**********************************************************\n\n"); 
}




int main()
{
	LinkedList mylist;
	mylist.InitLinkedList();
	mylist.show();
	while(1)
	{
		printf("请输入想要进行的操作(1:分配内存,2:回收内存 3:显示内存信息 4:退出系统)\n");
		int oper=0;
		scanf("%d",&oper);
		if(oper==1)
		{
			while(1)
			{
				printf("请输入想要进行的分配算法(1:首次适应算法,2:最佳适应算法,3:取消分配)\n");
				int num=0;
				scanf("%d",&num);
				if(num==3)
				{
					break;
				} 
				
				int request=0;
				printf("请输入要分配的内存大小\n");
				scanf("%d",&request);
				if(request<0)
				{
					printf("内存分配不能为负!\n");
					continue;
				}
				
				if(num==1)
				{
					if(mylist.first_fit(request))
					{
						printf("内存分配成功!\n");
					}
					else
					{
						printf("内存申请过多,分配失败!\n");
					}
					break;
				}
				else if(num==2)
				{
					if(mylist.best_fit(request))
					{
						printf("内存分配成功!\n");
					}
					else
					{
						printf("内存申请过多,分配失败!\n");
					}
					break;
				}
				else
				{
					printf("您输入的分配算法操作符号有误,请重新输入!\n");
					continue;
				}
			}
		}
		else if(oper==2)
		{
			int num=0;
			printf("请输入回收区分区序号\n");
			scanf("%d",&num);
			if(num==0)
			{
				printf("不能删除头结点\n");
				continue;
			}
			if(mylist.recovery(num))
			{
				printf("回收成功!\n");
			}
			else
			{
				printf("没有查到该分区序号\n");
			}
		}
		else if(oper==3)
		{
			mylist.show();
		}
		else if(oper==4)
		{
			break;
		}
		else
		{
			printf("您输入的操作有误,请重新输入!\n");
			continue;
		}
	}
	return 0;
}

运行截图如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 24
    点赞
  • 105
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值