版权声明:私藏源代码是违反人性的罪恶行为!博客转载无需告知,学无止境。 https://blog.csdn.net/qq_41822235/article/details/86249875
参考资料内存管理模拟实验
一、项目概述
1.1 理论
以空闲分区表数据结构实现动态分区分配,以首次适应算法(First Fit)进行内存的分配。虽然空闲分区表相对于空闲分区链而言更为简单,但是对我们理解现代操作系统的内存分配大有裨益。理解了空闲分区表的思想,空闲分区链一脉相承。
分区号 | 分区大小 | 分区始址 | 状态 |
---|---|---|---|
1 |
50 | 85 | 空闲 |
2 | 32 | 155 | 空闲 |
3 | 70 | 275 | 空闲 |
4 | 60 | 532 | 空闲 |
5 | ... | ... | ... |
1.2 数据结构设计
要描述如上所示的空闲分区表,最好的数据结构就是数组:
typedef struct Item
{
char *addr; //分区始址
int size; //大小
int tag; //标记 0空闲 1占用
}Item;
数组元素就是Item,现定义表格:
typedef struct Table
{
Item *data; //数组指针
int cursize; //当前元素个数
int capacity; //容量
}Table;
将数组定义成指针类型,方便进行扩容。
1.3 API设计
//初始化空闲分区表和已分配分区表
void init();
//根据作业长度找到顺序找到第一个适合该作业的区块,返回区块位置
int findSpace(int &job_length);
//对表进行扩容, incre为扩容倍数
void increCapacity(Table &tb, int incre);
//首次适应算法
void *FirstFit();
//打印输出空闲分区表
void showIdlePartition();
//打印输出已分配分区表
void showUsedPartition();
//撤销分区
void cancel();
//打印输出菜单
void printHint();
//根据输入的选项进行选择
void makeChoice(int choice);
二、C++实现
2.1 区块分配流程
2.2 区块回收流程
本流程主要描述了内存区块回收的四类情况:上邻接、下邻接、上下均邻接、上下均不邻接。
2.3 编程实现
将分配区的首地址返回给调用者是本项目的核心之所在。
必要准备:
#include<iostream>
#include<string.h> //memset()
#include<stdio.h> //printf()
#include<malloc.h>
#include<assert.h> //assert()
using namespace std;
#define CAPACITY 20 //数组容量
#define CURSIZE 10 //已用大小
//描述区块大小的情况
#define INITIALSIZE 10 //初始大小
#define INCREMENT 30 //分区增量
void *place = (void*)malloc(1000);
typedef struct Item
{
char *addr; //起始地址
int size; //空间大小
int tag; //标记
}Item; //表项
typedef struct Table
{
Item *data; //在这里之所以设置指针是为了将来扩容的需要
int cursize; //当前元素个数
int capacity; //容量
}Table; //表结构
Table frees, occupys; //空闲分区 已分配分区
init函数实现:
void init()
{
//初始化空闲分区表
frees.capacity = CAPACITY;
frees.cursize = INITIALSIZE;
frees.data = new Item[frees.capacity];
assert(NULL != frees.data);
frees.data[0].addr = (char*)place;
frees.data[0].size = INITIALSIZE;
frees.data[0].tag = 0;
for(int i = 1; i < frees.cursize; ++i)
{
frees.data[i].addr = frees.data[i-1].addr + frees.data[i-1].size;
frees.data[i].size = frees.data[i-1].size + INCREMENT;
frees.data[i].tag = 0;
}
//初始化已分配分区表
occupys.capacity = CAPACITY;
occupys.data = new Item[occupys.capacity];
assert(NULL != occupys.data);
occupys.cursize = 0;
memset(occupys.data, 0, occupys.capacity);
}
findSpace实现:
int findSpace(int &job_length) //找到第一个合适的区块
{
cout<<"输入作业大小:"<<endl;
cin>>job_length;
int pos = -1; //记录可用的第一个分区的大小
for(int i = 0; i < frees.cursize; ++i) //检索是否有合适大小
{
if(frees.data[i].size >= job_length)
{
pos = i;
break;
}
}
return pos;
}
increCapacity实现
void increCapacity(Table &tb, int incre) //扩容函数
{
if(incre <= 1) //扩容函数不实现缩减空间
return;
Item *tmp = tb.data;
tb.data = new Item[incre * tb.capacity];
assert(NULL != tb.data);
memset(tb.data, 0, tb.capacity*2);
for(int i = 0; i < tb.capacity; ++i)
tb.data[i] = tmp[i];
delete []tmp; //释放原有空间避免内存泄漏
tb.capacity *= incre;
}
首次适应算法
void* FirstFit() //首次适应算法
{
void *res_addr; //返回申请到的空间的首地址
int job_length = 0;
int pos = findSpace(job_length);
if(pos == -1)
{
cout<<"没有可用空间"<<endl;
return NULL;
}
res_addr = (void*)frees.data[pos].addr;
//没有在if判断时return 说明确实存在可用空间
//已用分区表已满需扩容
if(occupys.cursize == occupys.capacity)
{
increCapacity(occupys, 2);
}
//模拟进行进行分配的过程,注意已用空间数量+1
occupys.data[occupys.cursize].addr = frees.data[pos].addr;
occupys.data[occupys.cursize].size = job_length;
occupys.data[occupys.cursize].tag = 1;
occupys.cursize++;
if(frees.data[pos].size > job_length) //可用分区大小超过申请的大小
{
frees.data[pos].addr += job_length; //修改该可用分区始址
frees.data[pos].size -= job_length; //修改该可用分区大小
}else //可用分区的大小恰好等于申请的大小
{
for(int j = pos; j < frees.cursize-1; ++j)
frees.data[j] = frees.data[j+1];
frees.cursize--; //可用分区数减1
}
cout<<"空间申请成功\n";
return res_addr;
}
打印输出空闲分区
void showIdlePartition() //打印输出空闲分区表
{
cout<<"----------------------------------------------------------\n";
cout<<"当前空闲分区表如下"<<endl;
cout<<"编号 起始地址 长度 状态 "<<endl;
for(int i = 0; i < frees.cursize; ++i)
printf("%-4d%-10p%-10d%-2d\n",i ,frees.data[i].addr, frees.data[i].size, frees.data[i].tag);
cout<<"----------------------------------------------------------\n";
}
打印输出已用分区
void showUsedPartition() //打印输出已用分区表
{
cout<<"----------------------------------------------------------\n";
cout<<"当前已分配分区表如下"<<endl;
cout<<"编号 起始地址 长度 状态 "<<endl;
for(int i = 0; i < occupys.cursize; ++i)
printf("%-4d%-10p%-10d%-2d\n",i ,occupys.data[i].addr, occupys.data[i].size, occupys.data[i].tag);
cout<<"----------------------------------------------------------\n";
}
撤销作业
void cancel() //撤销作业
{
cout<<"请输入回收区的编号"<<endl;
int num;
cin>>num;
if(num < 0 || num >= occupys.capacity)
{
cout<<"输入错误,返回"<<endl;
return;
}
//取出待回收的区块
Item finish = occupys.data[num];
int i;
for(i = num; i < occupys.cursize-1;++i)
occupys.data[i] = occupys.data[i+1];
occupys.cursize -= 1;
if(frees.cursize == frees.capacity) //对空闲分区表2倍扩容
increCapacity(frees,2);
int pos; //pos记录插入点前一个
for(int i = 0; i < frees.capacity; ++i)
{
if(frees.data[i].addr+frees.data[i].size <= finish.addr || frees.data[i].size == 0)
{
pos = i;
break;
}
}
if(frees.data[pos].size == 0) //如果空闲分区表该项未使用直接放入
{
frees.data[pos].addr = finish.addr;
frees.data[pos].size = finish.size;
frees.data[pos].tag = 0;
return;
}
if(frees.data[pos].addr+frees.data[pos].size == finish.addr) //满足上邻接
{
frees.data[pos].size += finish.size; //和上空闲区域合并
if(frees.data[pos+1].addr == finish.addr+finish.size) //满足同时还满足下邻接 表项数会改变
{
frees.data[pos].size += frees.data[pos+1].size;
for(int i = pos+1; i < frees.cursize-1; ++i)
{
frees.data[i] = frees.data[i+1];
}
frees.cursize--;
}
}else //不满足上邻接
{
if(frees.data[pos+1].addr == finish.addr+finish.size) //满足下邻接
{
frees.data[pos+1].addr = finish.addr;
frees.data[pos+1].size += finish.size;
}else //不满足下邻接 表项数改变
{
for(int i = frees.cursize-1; i >= pos+1 ; --i)
{
frees.data[i+1] = frees.data[i];
}
frees.data[pos+1].addr = finish.addr;
frees.data[pos+1].size = finish.size;
frees.data[pos+1].tag = 0;
frees.cursize++;
}
}
}
输出提示信息
void printHint()
{
printf(" |--------------------------------------------------|\n");
printf(" | 可变分区存储管理模拟系统 |\n");
printf(" |--------------------------------------------------|\n");
printf(" | 菜单: (0)退出 |\n");
printf(" | |\n");
printf(" | (1)申请空间 (2)撤消作业 |\n");
printf(" | |\n");
printf(" | (3)显示空闲表 (4)显示分配表 |\n");
printf(" |--------------------------------------------------|\n");
}
根据用户的选择转调函数
void makeChoice(int choice) //接受用户的选择
{
switch(choice)
{
case 0:
break;
case 1:
FirstFit();
break;
case 2:
cancel();
break;
case 3:
showIdlePartition();
break;
case 4:
showUsedPartition();
break;
default:
break;
}
}
main主函数
int main()
{
init(); //初始化空闲分区表
printHint(); //打印输出提示信息
while(1)
{
int choice;
cout<<"请选择 0(退出) 1(申请空间) 2(撤销作业) 3(显示空闲表) 4(显示分配表):";
fflush(stdout);
cin>>choice;
if(choice < 0 || choice > 4)
{
cout<<"请重新选择"<<endl;
continue; //结束本次循环
}
if(0 == choice) //结束man主函数
{
delete []frees.data;
delete []occupys.data;
return 0;
}
makeChoice(choice); //根据用户的输入做出选择
}
return 0;
}
2.4 运行结果
申请空间
回收空间