【操作系统实验 / C++】在分页管理方式下采用位示图来表示主存分配情况,实现主存分配和回收(附代码)

1、选题及题目要求

在分页管理方式下采用位示图来表示主存分配情况,实现主存分配和回收
(1) 假定系统的主存被分成大小相等的64个块,用0/1对应空闲/占用。
(2) 当要装入一个作业时,根据作业对主存的需求量,先查空闲块数是否能满足作业要求,若能满足,则查位示图,修改位示图和空闲块数。位置与块号的对应关系为:

块号 = j * 8 + i,其中 i 表示位,j 表示字节。
根据分配的块号建立页表。页表包括两项:页号和块号。

(3) 回收时,修改位示图和空闲块数。
要求能接受来自键盘的空间申请及释放请求,能显示位示图和空闲块数的变化,能显示进程的页表。

2、数据结构设计

根据题目要求,分别设置了两组结构,用于存储位示图和作业。

struct BitMap       //用于存储位示图   
{  
    int map[8][8];  //8*8=64,位示图   
    int free;       //剩余的空闲块数   
}bitmap;  
 
typedef struct process      //用于存储作业   
{  
	int num;                //作业序号   
	int size;               //作业大小   
	int *pagetable;         //页表   
	struct process *next;   //下一作业   
	struct process *pre;    //上一作业   
}process; 
  • 其中位示图采用全局数组储存,0代表空闲,1代表占用。作业采用指针结构储存,使用队列的形式储存和释放,每输入一个新的作业,将其作为头指针插入队列,删除时则遍历队列,找到对应作业并删除。
  • 同时,在作业中设立一个不定项的数组指针,用于存储页表,在输入作业的大小后,创建一个相应大小的数组,并按序存储内存块号,同时修改位示图。删除时,也通过读取页表来修改位示图。

3、程序主要思路和原理

主要思路:

  • 针对作业,采用队列结构连接链表,其中头指针置为空,每输入一个新作业时,将其作为头指针的下一指针前插入链表,将下一作业的上一指针置为当前作业,同时当前作业的下一指针置为下一作业。剔除时同理,首先遍历链表,找到所有符合条件(即进程号为输入值)的进程,并依次修改当前指针的前指针和后指针。采用双指针结构避免出现数据错误。
  • 针对内存和位示图,每输入一个新作业时,首先检查当前是否有足够的内存块使用,如果有则修改位示图和free数据,并且产生相应的页表。释放作业时,也修改位示图和free数据。

原理:链表,头插法队列,指针,全局数组

4、程序运行结果

  • 运行程序,出现如下图所示的程序菜单。

在这里插入图片描述

  • 选择1操作,创建一个新作业并输入作业序号、作业大小,随后装入作业并生成页表,如下图所示。

在这里插入图片描述

  • 随机创建几个新作业,随后回收其中序号2的作业,如下图所示。

在这里插入图片描述

  • 此时查看位示图,如下图所示。
    在这里插入图片描述
  • 选择展示序号为23的作业页表,结果如下图所示。
    在这里插入图片描述

可见,未出现程序错误,且程序运行结果正常,该实验完成。

5、详细代码

#include <iostream>
#include <stdio.h>
using namespace std;

struct BitMap		//用于存储位示图 
{
	int map[8][8];	//8*8=64,位示图 
	int free;		//剩余的空闲块数 
}bitmap;

typedef struct process		//用于存储作业 
{
	int num;				//作业序号 
	int size;				//作业大小 
	int *pagetable;			//页表 
	struct process *next;	//下一作业 
	struct process *pre;	//上一作业 
}process;


void SetProcess(process *head)		//创立作业,生成页表 
{
	int setnum;
	int i=0,j=0,k=0,finish=0;
	process *temp = new process();
	cout<<endl<<"请输入作业序号(数字且不为0):";
	cin>>setnum;
	
	if(setnum == 0)
	{
		cout<<endl<<"错误!不能创建0号作业,返回。";
		delete temp;
		return;
	}
	
	temp->num = setnum;
	cout<<endl<<"请输入作业大小(<=64):";
	cin>>temp->size;
	
	if(temp->size > bitmap.free)		//判断现有空间是否足够分配 
	{
		cout<<endl<<"当前内存没有足够的空间分配,返回。";
		delete temp;
		return;
	}
	
	temp->next = head->next;	//头插法插入新作业 
	if(head->next != NULL)
		head->next->pre = temp;
	temp->pre = head;
	head->next = temp;
	
	temp->pagetable = new int [temp->size];	//创立页表数组 
	for(i=0; i<8 && finish == 0; i++)
	{
		for(j=0; j<8 && finish == 0; j++)
		{
			if(bitmap.map[i][j] == 0)		//修改页表数据 
			{
				bitmap.map[i][j] = 1;
				bitmap.free --;
				temp->pagetable[k] = 8*i + j;
				k++;
			}
			
			if(k == temp->size)		//用于结束循环 
				finish = 1;
		}
	} 
	
	cout<<endl<<"已装入作业,页表如下:"<<endl<<"页号\t";		//输出页表 
	k = temp->size;
	for(i=0; i<k; i++)
	{
		cout<<i+1<<'\t';
	}
	cout<<endl<<"块号\t";
	for(j=0; j<k; j++)
	{
		cout<<temp->pagetable[j]<<'\t';
	}
}


void RecProcess(process *head)		//回收作业,退还内存 
{
	int recnum;
	int i=0,j=0,k=0,l=0,found=0;
	process *temp = new process();
	cout<<endl<<"请输入回收作业序号(数字且不为0):";
	cin>>recnum;
	
	if(recnum == 0)
	{
		cout<<endl<<"错误!不能删除0号作业,返回。";
		return;
	}
	
	for(temp=head; temp != NULL; temp = temp->next)		//找到进程 
	{
		if(temp->num == recnum)
		{
			found = 1;
			k = temp->size;
			for(l=0; l<k; l++)		//删除数据 
			{
				i = temp->pagetable[l] / 8;
				j = temp->pagetable[l] % 8;
				bitmap.map[i][j] = 0;
				bitmap.free ++;
			}
			
			if(temp->pre != NULL)		//不允许删除头结点 
			{
				if(temp->next != NULL)		//不是尾结点 
				{
					temp->pre->next = temp->next;
					temp->next->pre = temp->pre;
					delete temp;
				}
				
				else						//是尾结点 
				{
					temp->pre->next = NULL;
					delete temp;
				}
			}
			
			cout<<endl<<"已找到并回收序号为"<<recnum<<"的作业。";
			cout<<endl<<"该作业大小为"<<k<<"。"<<endl;
			continue;
		}
	}
	
	if(found == 0)		//未找到进程 
	{
		cout<<endl<<"未找到该作业,返回。";
		return;
	}
	
	cout<<endl<<"完成回收,返回。";
	return;
}


void ShowBitMap()		//展示位示图 
{
	cout<<endl<<"当前位示图状态如下:"<<endl;
	cout<<'\t'<<"0\t"<<"1\t"<<"2\t"<<"3\t"<<"4\t"<<"5\t"<<"6\t"<<"7\t";
	cout<<endl<<"****";
	 
	int i=0,j=0;
	for(i=0; i<8; i++)
	{
		cout<<endl<<i<<'\t';
		for(j=0; j<8; j++)
		{
			cout<<bitmap.map[i][j]<<'\t';
		}
	}
	
	cout<<endl<<endl<<"完成位示图展示,返回。";
}


void ShowPageTable(process *head)		//展示页表 
{
	int shownum;
	int i=0,j=0,k=0,l=0,found=0;
	process *temp = new process();
	cout<<endl<<"请输入查看作业序号(数字且不为0):";
	cin>>shownum;
	
	if(shownum == 0)
	{
		cout<<endl<<"错误!不能查看0号作业,返回。";
		return;
	}
	
	for(temp=head; temp != NULL; temp = temp->next)		//找到进程 
	{
		if(temp->num == shownum)
		{
			found = 1; 
			cout<<endl<<"序号为"<<shownum<<"的作业页表如下:"<<endl<<"页号\t";		//输出页表 
			k = temp->size;
			for(i=0; i<k; i++)
			{
				cout<<i+1<<'\t';
			}
			cout<<endl<<"块号\t";
			for(j=0; j<k; j++)
			{
				cout<<temp->pagetable[j]<<'\t';
			}
			
			cout<<endl<<"已找到并展示序号为"<<shownum<<"的作业页表。";
			cout<<endl<<"该作业大小为"<<k<<"。"<<endl;
			continue;
		}
	}
	
	if(found == 0)		//未找到进程 
	{
		cout<<endl<<"未找到该作业,返回。";
		return;
	}
	
	cout<<endl<<"完成作业页表展示,返回。"; 
}


int main()
{
	char choice;
	bitmap.map[8][8] = 0;
	bitmap.free = 64;
	
	process *head = new process();
	head->next = NULL;
	head->pre = NULL;
	head->num = 0;
	
	do
	{
		cout<<endl; 
		cout<<endl<<"-----------操作列表-----------";
		cout<<endl<<"------------------------------";
		cout<<endl<<"0.退出程序;";
		cout<<endl<<"1.创建新作业,并请求内存空间;";
		cout<<endl<<"2.回收作业,并返回内存;";
		cout<<endl<<"3.展示位示图;";
		cout<<endl<<"4.展示进程页表;";
		cout<<endl<<"5.清空屏幕。";
		cout<<endl<<"------------------------------"; 
		cout<<endl<<"**请选择您要进行的操作:";
		
		cin>>choice;
		
		switch(choice)
		{
			case '1':
				SetProcess(head);
				break;
			case '2':
				RecProcess(head);
				break;
			case '3':
				ShowBitMap();
				break;
			case '4':
				ShowPageTable(head);
				break;
			case '5':
				system("cls");
				break;
			default:
				cout<<endl<<"输入错误!请重新输入!"; 
		}
	}while(choice != '0');
	
	return 0;
}

注:水平较菜,可能存在代码不简洁的部分,但是代码实测是可以跑的,仅供思路参考~

  • 7
    点赞
  • 73
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
基本分页存储管理方式下,内存被分为若干固定大小的页框,而进程所需的空间被划分为若干个大小相等的页面,每个进程有自己的页表来描述它所拥有的页面。在这种情况下,内存的分配回收可以通过以下方式实现: 1. 内存分配 首先,需要一个数据结构来记录内存中所有的页框的使用情况,可以使用一个位图来表示。每个位对应一个页框,如果该页框已经被分配给进程,则相应的位被标记为1,否则为0。当进程请求内存时,需要遍历位图,找到第一个连续的空闲页框,将它们标记为已分配,并返回它们的起始地址作为分配的内存空间。 2. 内存回收 当进程结束时,需要将其占用的内存空间释放回来。这可以通过清除页表中相应的页面条目以及标记位图中相应的位来完成。具体来说,可以遍历进程的页表,将其中所有指向已分配页面的条目清除,然后在位图中将对应的位清零即可。 下面是C++代码实现: ```c++ #include <iostream> #include <cstring> using namespace std; const int PAGE_SIZE = 4; // 页面大小 const int NUM_PAGES = 16; // 内存中页面数 const int NUM_FRAMES = 4; // 内存中页框数 struct PageTableEntry { int frameNum; // 页框号 bool valid; // 是否有效 }; class MemoryManager { public: MemoryManager() { memset(bitmap, 0, sizeof(bitmap)); // 初始化位图 for (int i = 0; i < NUM_FRAMES; i++) { bitmap[i] = false; } } void* allocate(int numPages) { if (numPages <= 0 || numPages > NUM_PAGES) { return nullptr; // 分配失败 } int start = -1; for (int i = 0; i < NUM_FRAMES; i++) { if (bitmap[i] == false) { if (start == -1) { start = i; } if (i - start + 1 == numPages) { break; } } else { start = -1; } } if (start == -1) { return nullptr; // 分配失败 } for (int i = start; i < start + numPages; i++) { bitmap[i] = true; // 标记为已分配 } return (void*)(start * PAGE_SIZE); // 返回起始地址 } void deallocate(PageTableEntry* pageTable) { for (int i = 0; i < NUM_PAGES; i++) { if (pageTable[i].valid) { int frameNum = pageTable[i].frameNum; bitmap[frameNum] = false; // 标记为未分配 pageTable[i].valid = false; // 清除页表条目 } } } private: bool bitmap[NUM_FRAMES]; }; int main() { MemoryManager memMgr; PageTableEntry pageTable[NUM_PAGES]; void* ptr1 = memMgr.allocate(2); // 分配2个页面 if (ptr1 == nullptr) { cout << "Allocation failed." << endl; return 0; } for (int i = 0; i < 2; i++) { pageTable[(int)ptr1 / PAGE_SIZE + i].frameNum = (int)ptr1 / PAGE_SIZE + i; pageTable[(int)ptr1 / PAGE_SIZE + i].valid = true; // 填充页表 } void* ptr2 = memMgr.allocate(3); // 分配3个页面 if (ptr2 == nullptr) { cout << "Allocation failed." << endl; return 0; } for (int i = 0; i < 3; i++) { pageTable[(int)ptr2 / PAGE_SIZE + i].frameNum = (int)ptr2 / PAGE_SIZE + i; pageTable[(int)ptr2 / PAGE_SIZE + i].valid = true; // 填充页表 } memMgr.deallocate(pageTable); // 释放内存 return 0; } ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值