C++ 操作系统内存分配算法的实现详解

目录
  • 一、实验目的
  • 二、实验内容
  • 三、实验要求
  • 四、代码实现
  • 五、测试样例

一、实验目的

通过本实验帮助学生理解在动态分区管理方式下应怎样实现主存空间的分配和回收。

二、实验内容

在动态分区管理方式下采用不同的分配算法实现主存分配和实现主存回收。

三、实验要求

(1)可变分区方式是按作业需要的主存空间大小来分割分区的。当要装入一个作业时,根据作业需要的主存量查看是否有足够的空闲空间,若有,则按需要量分割一个分区分配给该作业;若无,则作业不能装入。随着作业的装入、撤离、主存空间被分成许多个分区,有的分区被作业占用,而有的分区是空闲的。例如:

为了说明哪些区是空闲的,可以用来装入新作业,必须要有一张空区说明表,格式如下:

其中
起址——指出一个空闲区的主存起始地址。
长度——指出从起始地址开始的一个连续空闲区的长度。
状态——有两种状态,一种是“未分配”状态,指出对应的由起址指出的某个长度的区域是空闲区;另一种是“空表目”状态,表示表中对应的登记项目是空白(无效),可用来登记新的空闲区(例如,作业撤离后,它所占的区域就成了空闲区,应找一个“空表目”栏登记归还区的起址和长度且修改状态)。
由于分区的个数不定,所以空闲区说明表中应有适量的状态为“空表目”的登记栏目,否则造成表格“溢出”无法登记。

上述的这张说明表的登记情况是按提示

(1)中的例所装入的三个作业占用的主存区域后填写的

(2)当有一个新作业要求装入主存时,必须查空闲区说明表,从中找出一个足够大的空闲区。有时找到的空闲区可能大于作业需要量,这时应把原来的空闲区变成两部分:一个部分分给作业占用;另一部分又成为一个较小的空闲区。为了尽量减少由于分割造成的“碎片”,在作业请求装入时,尽可能地利用主存的低地址部分的空闲区,而尽量保存高地址部分有较大的连续空闲区域,以利于大型作业的装入。为此,在空闲区说明表中,把每个空闲区按其地址顺序登记,即每个后继的空闲区其起始地址总是比前者大。为了方便查找还可使表格“紧缩”,总是让“空表目”栏集中在表格的后部。

(3)采用首次适应算法或循环首次算法或最佳适应算法分配主存空间。由于本实验是模拟主存的分配,所以当把主存区分配给作业后并不实际启动装入程序装入作业,而用输出“分配情况”来代替。(即输出当时的空闲区说明表及其内存分配表)

(4)当一个作业执行结束撤离时,作业所占的区域应该归还,归还的区域如果与其它空闲区相邻,则应合成一个较大的空闲区,登记在空闲区说明表中。例如,在提示(1)中列举的情况下,如果作业2撤离,归还所占主存区域时,应与上、下相邻的空闲区一起合成一个大的空闲区登记在空闲区说明表中。

(5)请分别按首次适应算法、循环首次算法和最佳适应算法设计主存分配和回收的程序。然后按(1)中假设主存中已装入三个作业,且形成两个空闲区,确定空闲说明表的初值。现有一个需要主存量为6K的作业4 申请装入主存;然后作业3 撤离;再作业2 撤离。请你为它们进行主存分配和回收,把空闲区说明表的初值以及每次分配或回收后的变化显示出来或打印出来。

四、代码实现

MemoryAllocation.cpp

#include <iostream>
#include <Windows.h>
#include <fstream>
#include <string>
#include <queue>
using namespace std;
int MemorySize = 0;
int OSSize = 0;
int Memory[1000] = { 0 };

struct Struct1{
 	int begin;
	int length;
	string state;//值为未分配或者空条目
};
queue<Struct1> WORK;//作业集合
queue<Struct1> EMPTY;//空区集合

//更新EMPTY队列,空区集合
void UpdateEMP(){
	while (!EMPTY.empty()) {
		EMPTY.pop();
	}

	for (int i = 0; i < MemorySize; i++) {
		if (Memory[i] == 0) {
			for (int j = i + 1; j < MemorySize; j++) {
				if (Memory[j] == 1 || j == MemorySize - 1) {
					Struct1 emp1;
					emp1.begin = i;
					if (j == MemorySize - 1) {
						emp1.length = j - i + 1;
					}
					else {
						emp1.length = j - i;
					}
					emp1.state = "未分配";
					EMPTY.push(emp1);
					i = j;
					break;
				}
			}
		}
	}
	cout << "现有的空区说明表为:" << endl;
	int s = EMPTY.size();
	cout << s << "块空区" << endl;
	for (int i = 0; i < s; i++) {
		Struct1 emp1;
		emp1 = EMPTY.front();
		EMPTY.push(emp1);
		EMPTY.pop();
		cout  << " 起始:" << emp1.begin << " 长度:" << emp1.length << " 状态:" << emp1.state << endl;
	}
}

//首次适应算法(FF)
void FF(int applyNum) {
	if (EMPTY.empty()) {
		cout << "没有足够的主存空间!!" << endl;
		exit(0);
	}
	bool flag = false;
	while (!EMPTY.empty()) {
		Struct1 emp1 = EMPTY.front();
		if (emp1.length > applyNum) {
			for (int i = emp1.begin; i< applyNum + emp1.begin ;i++) {
				Memory[i] = 1;
			}
			Struct1 work3;
			work3.begin = emp1.begin;
			work3.length = applyNum;
			work3.state = "作业4";
			WORK.push(work3);
			UpdateEMP();
			flag = true;
			break;
		}
		EMPTY.pop();

	}
	if (!flag) {
		cout << "没有足够的主存空间!!" << endl;
		exit(0);
	}
	Sleep(2000);
	//作业三撤离
	for (int i = 0; i < WORK.size(); i++) {
		Struct1 work1;
		work1 = WORK.front();
		if (work1.state == "作业3") {
			for (int i = work1.begin; i < work1.begin+ work1.length;i++) {
				Memory[i] = 0;
			}
			WORK.pop();
			cout << endl << "作业三撤离!" << endl;
			UpdateEMP();
			break;
		}
		else {
			WORK.pop();
			WORK.push(work1);
		}
	}
	Sleep(2000);
	//作业二撤离
	for (int i = 0; i < WORK.size(); i++) {
		Struct1 work1;
		work1 = WORK.front();
		if (work1.state == "作业2") {
			for (int i = work1.begin; i < work1.begin + work1.length; i++) {
				Memory[i] = 0;
			}
			WORK.pop();
			cout << endl << "作业二撤离!" << endl;
			UpdateEMP();
			break;
		}
		else {
			WORK.pop();
			WORK.push(work1);
		}
	}

}

//循环首次适应算法(NF)
void NF(int applyNum) {
	if (EMPTY.empty()) {
		cout << "没有足够的主存空间!!" << endl;
		exit(0);
	}
	bool flag = false;
	while (!EMPTY.empty()) {
		Struct1 emp1 = EMPTY.front();
		if (emp1.length > applyNum) {
			for (int i = emp1.begin; i < applyNum + emp1.begin; i++) {
				Memory[i] = 1;
			}
			Struct1 work3;
			work3.begin = emp1.begin;
			work3.length = applyNum;
			work3.state = "作业4";
			WORK.push(work3);
			UpdateEMP();
			flag = true;
			break;
		}
		EMPTY.pop();

	}
	if (!flag) {
		cout << "没有足够的主存空间!!" << endl;
		exit(0);
	}
	Sleep(2000);
	//作业三撤离
	for (int i = 0; i < WORK.size(); i++) {
		Struct1 work1;
		work1 = WORK.front();
		if (work1.state == "作业3") {
			for (int i = work1.begin; i < work1.begin + work1.length; i++) {
				Memory[i] = 0;
			}
			WORK.pop();
			cout << endl << "作业三撤离!" << endl;
			UpdateEMP();
			break;
		}
		else {
			WORK.pop();
			WORK.push(work1);
		}
	}
	Sleep(2000);
	//作业二撤离
	for (int i = 0; i < WORK.size(); i++) {
		Struct1 work1;
		work1 = WORK.front();
		if (work1.state == "作业2") {
			for (int i = work1.begin; i < work1.begin + work1.length; i++) {
				Memory[i] = 0;
			}
			WORK.pop();
			cout << endl << "作业二撤离!" << endl;
			UpdateEMP();
			break;
		}
		else {
			WORK.pop();
			WORK.push(work1);
		}
	}
}

//最佳适应算法(BF)
void BF(int applyNum) {
	if (EMPTY.empty()) {
		cout << "没有足够的主存空间!!" << endl;
		exit(0);
	}
	bool flag = false;
	int col = 10000000;//记录每一个空区与请求大小的差值
	string e = "";
	int em = EMPTY.size()*2;
	for (int i = 0; i < em; i++) {
		Struct1 emp1 = EMPTY.front();
		if (emp1.length > applyNum) {
			if (col == (emp1.length - applyNum) && e==emp1.state) {
				for (int i = emp1.begin; i < applyNum + emp1.begin; i++) {
					Memory[i] = 1;
				}
				Struct1 work3;
				work3.begin = emp1.begin;
				work3.length = applyNum;
				work3.state = "作业4";
				WORK.push(work3);
				UpdateEMP();
				flag = true;
				break;
			}
			if (col > (emp1.length - applyNum)) {
				col = (emp1.length - applyNum);
				e = emp1.state;
			}
		}
		EMPTY.pop();
		EMPTY.push(emp1);
	}
	if (!flag) {
		cout << "没有足够的主存空间!!" << endl;
		exit(0);
	}
	Sleep(2000);
	//作业三撤离
	for (int i = 0; i < WORK.size(); i++) {
		Struct1 work1;
		work1 = WORK.front();
		if (work1.state == "作业3") {
			for (int i = work1.begin; i < work1.begin + work1.length; i++) {
				Memory[i] = 0;
			}
			WORK.pop();
			cout << endl << "作业三撤离!" << endl;
			UpdateEMP();
			break;
		}
		else {
			WORK.pop();
			WORK.push(work1);
		}
	}
	Sleep(2000);
	//作业二撤离
	for (int i = 0; i < WORK.size(); i++) {
		Struct1 work1;
		work1 = WORK.front();
		if (work1.state == "作业2") {
			for (int i = work1.begin; i < work1.begin + work1.length; i++) {
				Memory[i] = 0;
			}
			WORK.pop();
			cout << endl << "作业二撤离!" << endl;
			UpdateEMP();
			break;
		}
		else {
			WORK.pop();
			WORK.push(work1);
		}
	}
}

//主函数
int main() {
	//打印提示信息
	cout << "************************************************\n";
	cout << "        操作系统实验内存分配算法\n";
	cout << "        作者:CSDN Carmelo_7 主页: https://blog.csdn.net/Carmelo_7?spm=1000.2115.3001.5343 \n";
	cout << "************************************************\n";
	ifstream inFile;
	inFile.open("MemoryAllocation.dat");
	if (!inFile.is_open())
		cout << "文件打开时候出错!!" << endl;
	inFile >> MemorySize >> OSSize;
	cout << "请输入主存的现有状态" << endl;
	cout << "正在读取数据文件..." << endl;
	Sleep(2000);
	//打印空闲区说明表的初始状态
	cout << "主存总大小:" << MemorySize << endl <<"操作系统占用空间:" << OSSize <<endl;
	for (int i = 0;i<OSSize; i++) {
		Memory[i] = 1;
	}
	int n = 0;
	while (!inFile.eof()) {
		n++;
		Struct1 work1;
		inFile >> work1.begin >> work1.length;
		work1.state = "作业"+to_string(n);
		WORK.push(work1);
	}
	int s = WORK.size();
	for (int i = 0; i < s; i++) {
		Struct1 work2;
		work2 = WORK.front();
		WORK.push(work2);
		WORK.pop();
		cout << work2.state << " 起始:" << work2.begin << " 长度:" << work2.length << endl;
		for (int i = work2.begin; i < work2.length + work2.begin; i++) {
			Memory[i] = 1;
		}
	}
	/*for (int i : Memory) {
		cout << i;
	}*/

	UpdateEMP();

	cout << "请输入新的作业的申请主存数量:" << endl;
	//打印作业4的申请量
	int applyNum = 0;
	cin >> applyNum;
	cout << "作业" << n << "申请了"<< applyNum <<"主存空间" << endl;

	cout << "===================================================================================" << endl;
	cout << "1.首次适应算法(FF) :将所有空闲分区按照地址递增的次序链接,在申请内存分配时,从链首开始查找,将满足需求的第一个空闲分区分配给作业。" << endl;
	cout << "2.循环首次适应算法(NF):将所有空闲分区按照地址递增的次序链接,在申请内存分配时,总是从上次找到的空闲分区的下一个空闲分区开始查找,将满足需求的第一个空闲分区分配给作业" << endl;
	cout << "3.最佳适应算法(BF) : 将所有空闲分区按照从小到大的顺序形成空闲分区链,在申请内存分配时,总是把满足需求的、最小的空闲分区分配给作业。" << endl;
	cout << "===================================================================================" << endl;
	cout << "请输入对应的序号选择算法:" << endl;
	int choose = 0;
	cin >> choose;
	switch (choose)	{
		case 1:
			FF(applyNum);
			break;
		case 2:
			NF(applyNum);
			break;
		case 3:
			BF(applyNum);
			break;
		default:
			cout << "你输入的序号有误!!!" << endl;
			exit(0);
			break;
	}

}

MemoryAllocation.dat

128 5
5 5
26 6
10 4

五、测试样例

到此这篇关于C++ 操作系统内存分配算法的实现详解的文章就介绍到这了,更多相关操作系统内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C/C++内存管理详情

    目录 C/C++内存管理 1. C/C++内存分布 2. C语言中动态内存管理方式 2.1 malloc/calloc/realloc和free 3. C++内存管理方式 3.1 new/delete操作内置类型 3.2 new和delete操作自定义类型 4. operator new与operator delete函数 5. new和delete的实现原理 5.1.new 5.2.delete 5.3.new 数组 5.4.delete 数组 C/C++内存管理 内存管理是C++最令人切齿痛

  • C语言编程C++动态内存分配示例讲解

    目录 动态内存管理 为什么存在动态内存分配 动态内存函数的介绍 malloc申请空间和free释放空间 有借有还 free释放内存 calloc申请内存 realloc调整动态内存的大小 realloc使用的注意事项 当然realloc也可以直接开辟空间 常见的动态内存错误 1.对NULL指针的解引用操作 2.对动态开辟空间的越界访问 3.对非动态开辟内存使用free释放 4.使用free释放一块动态内存开辟的一部分 5.对同一块动态内存多次释放 6.动态开辟内存忘记释放(内存泄漏) 几个面试题

  • c/c++内存分配大小实例讲解

    测试平台:linux 32位系统 用sizeof()运算符计算分配空间大小.单位:字节 1. 数组名与变量名的区别 int main() { char q[] = "hello"; cout << "q:" << sizeof(q) << endl; char *mq = q; cout << "mq:" << sizeof(mq) << endl; const char *

  • C++ 操作系统内存分配算法的实现详解

    目录 一.实验目的 二.实验内容 三.实验要求 四.代码实现 五.测试样例 一.实验目的 通过本实验帮助学生理解在动态分区管理方式下应怎样实现主存空间的分配和回收. 二.实验内容 在动态分区管理方式下采用不同的分配算法实现主存分配和实现主存回收. 三.实验要求 (1)可变分区方式是按作业需要的主存空间大小来分割分区的.当要装入一个作业时,根据作业需要的主存量查看是否有足够的空闲空间,若有,则按需要量分割一个分区分配给该作业:若无,则作业不能装入.随着作业的装入.撤离.主存空间被分成许多个分区,有

  • 关于Java变量的声明、内存分配及初始化详解

    实例如下: class Person { String name; int age; void talk() { System.out.println("我是: "+name+", 今年: "+age+"岁"); } } public class TestJava2_1 { public static void main(String args[]) { Person p; if (p == null) { p = new Person(); }

  • Linux内核中红黑树算法的实现详解

    一.简介 平衡二叉树(BalancedBinary Tree或Height-Balanced Tree) 又称AVL树.它或者是一棵空树,或者是具有下列性质的二叉树:它的左子树和右子树都是平衡二叉树,且左子树和右子树的深度之差的绝对值不超过1.若将二叉树上结点的平衡因子BF(BalanceFactor)定义为该结点的左子树的深度减去它的右子树的深度,则平衡二叉树上所有结点的平衡因子只可能是-1.0和1.(此段定义来自严蔚敏的<数据结构(C语言版)>) 红黑树 R-B Tree,全称是Red-B

  • 应用OpenCV和Python进行SIFT算法的实现详解

    应用OpenCV和Python进行SIFT算法的实现 如下图为进行测试的gakki101和gakki102,分别验证基于BFmatcher.FlannBasedMatcher等的SIFT算法,对比其优劣.为体现出匹配效果对于旋转特性的优势,将图gakki101做成具有旋转特性的效果. 基于BFmatcher的SIFT实现 BFmatcher(Brute-Force Matching)暴力匹配,应用BFMatcher.knnMatch( )函数来进行核心的匹配,knnMatch(k-nearest

  • C语言动态内存泄露常见问题内存分配改进方法详解

    目录 一.例题 二.2种改进方法 法1:二级指针(传址调用) 法2:返回指针 总结 一.例题 试问该段代码能打印什么,或者不能打印什么,说出理由 #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<string.h> #include<stdlib.h> void getmemory(char*p) { p = (char*)malloc(100); } void test() { char*str =

  • PHP内存溢出优化代码详解

    相信很多人做大批量数据导出和数据导入的时候,经常会遇到PHP内存溢出的问题,在解决了问题之后,总结了一些经验,整理成文章记录下. 优化点 1.优化SQL语句,避免慢查询,合理的建立索引,查询指定的字段,sql优化这块在此就不展开了. 2.查询的结果集为大对象时转数组处理,框架中一般有方法可以转,如Laravel中有toArray(),Yii2中有asArray(). 3.对于大数组进行数据切割处理,PHP函数有array_chunk().array_slice(). 4.对于大型的字符串和对象,

  • Java基础之内存泄漏与溢出详解

    一.浅析 内存泄露( memory leak):是指程序在申请内存后,无法释放已申请的内存空间,多次内存泄露堆积后果很严重,内存迟早会被占光.内存泄漏最终会造成内存溢出. 内存溢出(out of memory) :是指程序在申请内存时,没有足够的内存空间供其使用 JVM中有一下几种内存空间: 栈内存(Stack):每个线程私有的. 堆内存(Heap):所有线程公用的. 方法区(Method Area):有点像以前常说的"进程代码段",这里面存放了每个加载类的反射信息.类函数的代码.编译

  • Java基础之Unsafe内存操作不安全类详解

    简介 Unsafe类使Java拥有了像C语言的指针一样操作内存空间的能力,直接操作内存就意味着 1.不受jvm管理,也就意味着无法被GC,需要我们手动GC,稍有不慎就会出现内存泄漏. 2.Unsafe的不少方法中必须提供原始地址(内存地址)和被替换对象的地址,偏移量要自己计算,一旦出现问题就是JVM崩溃级别的异常,会导致整个JVM实例崩溃,表现为应用程序直接crash掉. 3.直接操作内存,也意味着其速度更快,在高并发的条件之下能够很好地提高效率. Unsafe 类 public final c

  • Golang 内存管理简单技巧详解

    目录 引言 预先分配切片 结构中的顺序字段 使用 map[string]struct{} 而不是 map[string]bool 引言 除非您正在对服务进行原型设计,否则您可能会关心应用程序的内存使用情况.内存占用更小,基础设施成本降低,扩展变得更容易/延迟. 尽管 Go 以不消耗大量内存而闻名,但仍有一些方法可以进一步减少消耗.其中一些需要大量重构,但很多都很容易做到. 预先分配切片 数组是具有连续内存的相同类型的集合.数组类型定义指定长度和元素类型.数组的主要问题是它们的大小是固定的——它们

  • Performance 内存监控使用技巧详解

    目录 Performance 介绍 使⽤ 内存问题的具体体现 监控内存的⼏种⽅式 TimeLine Performance 介绍 为什么使⽤Performance呢?GC 的⽬的是为了实现内存空间的良性循环,⽽良性循环的基⽯是合理的使⽤内存空间. 由于 ECMAScript 并没有提供操作内存的 API,所以内存分配是否合理我们不可知.Performance 提供了多种⽅式,在程序运⾏时可以时时监控,确定内存分配是否合理. 使⽤ 具体步骤 打开浏览器输⼊⽬标⽹址 进⼊开发⼈员⼯具⾯板 开启录制功

随机推荐