第6次实验 内存分配与回收模拟

实验目的

  • 通过使用位图或空闲表,跟踪内存使用情况,模拟和评价不同的内存分配算法;

  • 熟悉内存分配和回收管理过程;

  • 要求用你熟悉的程序设计语言编写和调试一个内存分配和回收模拟程序

实验内容

  • 假设内存容量为256KB,并且划分成1KB大小的块,也即每个内存单元为1KB。一个进程所需要的内存为3到10个单元。同时假设一个作业在运行过程中所需内存的大小不变。

模拟包括3部分

  • 实现特定的内存分配算法(first fit,next fit, best fit, worst fit)四种

  • 实现内存回收模拟

  • 每种内存分配策略对应的碎片数统计(可选)

以下是四种内存分配算法过程和过程分析

  • 四种算法均用链表实现,并且带有显示此时空闲区的分配情况和显示进程链表和空闲区链表元素的功能

Fit fit(首次适配)

  • 遍历空闲区链表,当找到满足条件的空闲区时,判断空闲区长度是否恰好等于进程申请的长度,然后构造新进程放入进程链表中,保存此时空闲区的迭代器(用于下次适配),并更新分配大小的空闲区的起始地址和长度
  • 如果当前空闲区的长度为0时,在链表中删除此空闲区

  • ScanfProgramm是输入程序,inputId、inputSize是进程的id号和申请内存大小

Next fit(下次适配)

  • 在之前所有分配内存时,都将分配空闲区的迭代器通过全局变量的形式保存下来,所以在NextFit中,从上次迭代器的开头开始遍历空闲区链表
  • 当找到满足进程申请内存大小的空闲区时

Best fit(最佳适配)

  • 维护一个最大值difMin,遍历空闲区链表,当找到满足条件的空闲区时,将该空闲区大小-进程内存大小与difMin比较,更新difMin为两者的最大值,以找到满足进程申请的大小,且长度最小的空闲区
  • 并维护那个迭代器,当循环结束后,再构造新进程放入进程链表,保存此时的空闲区的迭代器(用于下次适配)

Worst fit(最坏适配)

  • 维护一个最小值difMax,遍历空闲区链表,当找到满足条件的空闲区时,将该空闲区大小-进程内存大小与difMax比较,更新difMax为两者的最小值,以找到满足进程申请的大小,且长度最大的空闲区
  • 并维护那个迭代器,当循环结束后,再构造新进程放入进程链表,保存此时的空闲区的迭代器(用于下次适配)

回收内存

  • 用户先输入要回收的进程号,然后在进程链表删除它
  • 涉及到空闲内存表的合并
    • 大致思路如下,空闲区链表中的数据为起始地址和内存长度,首先先将链表元素按照起始地址从小到大进行排序,这样可以方便进行合并
    • 初始化两个迭代器在链表头,一个迭代器指向另一迭代器的下一元素,当前一迭代器的起始地址+长度等于后一迭代器的起始地址时,更新后一迭代器的起始地址为前一迭代器的起始地址,长度为两者长度之和,然后删除前一迭代器指向的元素,并将当前的迭代器进行后移
  • 针对三种内存回收后的情况(回收前只存在单边有空闲区(2个)、回收前两边均是空闲区(1个)),均有效

全部代码(由C++链表实现)

#include <iostream>
#include <map>
#include <list>
#include <iomanip>
#include <algorithm>
using namespace std;struct EmptyArea // 未分配地址的空闲表
{int startAddress = 1000;int size_of_empty = 0;EmptyArea(int startAddress1, int size_of_empty1) :startAddress(startAddress1), size_of_empty(size_of_empty1) {}void PrintInfo() { cout << setiosflags(ios::right) << setw(8) << startAddress << "\t" << size_of_empty << endl; }bool operator<(const EmptyArea& e1) { return startAddress < e1.startAddress; }
};struct ProcessControlBlock // 进程表(非空闲表)
{int process_id;int startAddress;int size_of_process = 0;ProcessControlBlock(int process_id1, int startAddress1, int size_of_process1):process_id(process_id1), startAddress(startAddress1), size_of_process(size_of_process1) {}void PrintInfo() {cout << setiosflags(ios::right) << setw(6)<< process_id << "\t" << startAddress << "\t\t" << size_of_process << endl;}bool operator<(const ProcessControlBlock& p1) { return startAddress < p1.startAddress; }
};const int MAXSIZE = 256; // 最大内存大小
const int N = 20;
map<pair<int, int>, int> mapp;
list<EmptyArea>::iterator listEmptyAreaIterator;
list<EmptyArea> listEmptyArea;
list<ProcessControlBlock> listProcess;int inputId, inputSize;
char MemoryFoot[17][17];
int notEmptyStart = 0, lastAllocatIndex = 0;// 上次分配的起始地址,用于记录邻近适配int main();void init();
void printMenu();
void chooseFit();
void FirstFitMemory(); // 首次适配
void NextFitMemory(); // 下次适配
void BestFitMemory(); // 最优适配
void WorstFitMemory(); // 最坏适配
void RecoveryOfMemory(); // 回收内存
void PrintMemoryFoot(); // 打印内存占用情况
void PrintEmptyTableAndNotEmptyTable();
void ExitProgramm(); // 退出程序
void ScanfProgramm(); // 赋值int main() {init();while (1) {cout << "******************Memory Size : 256KB*******************" << endl;printMenu();chooseFit();}
}void FirstFitMemory()
{ScanfProgramm();//listEmptyArea.sort();// inputId inputSizefor (auto it = listEmptyArea.begin(); it != listEmptyArea.end(); ++it) {if (it->size_of_empty >= inputSize) {listProcess.push_back(ProcessControlBlock(inputId, it->startAddress, inputSize));it->startAddress = it->startAddress + inputSize;it->size_of_empty = it->size_of_empty - inputSize;if (it->size_of_empty == 0)   listEmptyArea.erase(it++);listEmptyAreaIterator = it;return;}}cout << "内存不足" << endl;
}void NextFitMemory()
{ScanfProgramm();//listEmptyArea.sort();// inputId inputSizefor (auto it = listEmptyAreaIterator; it != listEmptyArea.end(); ++it) {if (it->startAddress < listEmptyAreaIterator->startAddress) // 从迭代器下一元素开始遍历continue;if (it->size_of_empty >= inputSize) {listProcess.push_back(ProcessControlBlock(inputId, it->startAddress, inputSize));it->startAddress = it->startAddress + inputSize;it->size_of_empty = it->size_of_empty - inputSize;if (it->size_of_empty == 0)  listEmptyArea.erase(it++);listEmptyAreaIterator = it;return;}}cout << "内存不足" << endl;
}void BestFitMemory() // 最佳适配
{ScanfProgramm();int difMin = INT_MAX;bool findFlag = false;list<EmptyArea>::iterator it2;//listEmptyArea.sort();// inputId inputSizefor (auto it = listEmptyArea.begin(); it != listEmptyArea.end(); ++it) {if (it->size_of_empty >= inputSize) {if (it->size_of_empty - inputSize < difMin) {difMin = it->size_of_empty - inputSize;it2 = it;}findFlag = true;}}if (!findFlag)cout << "内存不足" << endl;else {listProcess.push_back(ProcessControlBlock(inputId, it2->startAddress, inputSize));it2->startAddress = it2->startAddress + inputSize;it2->size_of_empty = it2->size_of_empty - inputSize;if (it2->size_of_empty == 0)   listEmptyArea.erase(it2++);listEmptyAreaIterator = it2; // 成功找到才能适配对应的迭代器}
}void WorstFitMemory() // 最差适配
{ScanfProgramm();int difMax = INT_MIN;bool findFlag = false;//listEmptyArea.sort();list<EmptyArea>::iterator it2;// inputId inputSizefor (auto it = listEmptyArea.begin(); it != listEmptyArea.end(); ++it) {if (it->size_of_empty >= inputSize) {if (it->size_of_empty - inputSize > difMax) {difMax = it->size_of_empty - inputSize;it2 = it;}findFlag = true;}}if (!findFlag)cout << "内存不足" << endl;else {listProcess.push_back(ProcessControlBlock(inputId, it2->startAddress, inputSize));it2->startAddress = it2->startAddress + inputSize;it2->size_of_empty = it2->size_of_empty - inputSize;if (it2->size_of_empty == 0)   listEmptyArea.erase(it2++);listEmptyAreaIterator = it2; // 成功找到才能适配对应的迭代器}
}void RecoveryOfMemory()
{cout << "请输入要回收的进程号" << endl;int recoveryId;cin >> recoveryId;bool flag = false;// 删除进程for (auto it = listProcess.begin(); it != listProcess.end(); ++it) {if (it->process_id == recoveryId) {listEmptyArea.push_back(EmptyArea(it->startAddress, it->size_of_process));cout << "删除it :" << it->process_id << endl;listProcess.erase(it);flag = true;break;}}if (!flag) {cout << "不存在该进程,回收失败" << endl;return;}if (listEmptyArea.size() < 2)   return;listEmptyArea.sort();int startAddress, size_of_process;for (auto it = listEmptyArea.begin(), it2 = ++listEmptyArea.begin(); it2 != listEmptyArea.end(); ++it2) {startAddress = it->startAddress;size_of_process = it->size_of_empty;if (startAddress + size_of_process == it2->startAddress) { // 合并it2->startAddress = startAddress;it2->size_of_empty = it2->size_of_empty + size_of_process;listEmptyArea.erase(it++);}else it++;}
}void PrintMemoryFoot()
{for (auto it = listProcess.begin(); it != listProcess.end(); ++it) { // 遍历进程链表int startAddress = it->startAddress;int len = it->size_of_process;for (int i = 0; i < len; ++i) {int row = (startAddress + i) / 16;int col = (startAddress + i) % 16;if (!i) {MemoryFoot[row][col] = '-';mapp[make_pair(row, col)] = it->process_id;continue;}MemoryFoot[row][col] = '+';}}for (auto it = listEmptyArea.begin(); it != listEmptyArea.end(); ++it) { // 遍历空闲区链表 int startAddress = it->startAddress;int len = it->size_of_empty;for (int i = 0; i < len; ++i) {int row = (startAddress + i) / 16;int col = (startAddress + i) % 16;MemoryFoot[row][col] = '=';}}cout << "******************   Memory State   *******************" << endl << endl;// 16 X 16for (int i = 0; i < 16; ++i) {for (int j = 0; j < 16; ++j) {if (MemoryFoot[i][j] == '-')   cout << mapp[make_pair(i, j)];else cout << MemoryFoot[i][j];}cout << endl;}
}void init()
{for (int i = 0; i < 16; ++i)for (int j = 0; j < 16; ++j)MemoryFoot[i][j] = L'=';listEmptyArea.push_back(EmptyArea(0, MAXSIZE));
}void printMenu()
{cout << "1 First Fit分配\t2 Next Fit分配\t3 Best Fit分配\n4 Worst Fit分配\t5 回收\t6 内存占用情况图\t7 打印空闲表和非空闲表\t8 退出\n\n";cout << "请输入你的选择(1~7):\n>";
}void chooseFit()
{int choose;cin >> choose;switch (choose){case 1: {FirstFitMemory();PrintMemoryFoot();break;}case 2: {NextFitMemory();PrintMemoryFoot();break;}case 3: {BestFitMemory();PrintMemoryFoot();break;}case 4: {WorstFitMemory();PrintMemoryFoot();break;}case 5: {RecoveryOfMemory();PrintMemoryFoot();break;}case 6: {PrintMemoryFoot();break;}case 7: {PrintEmptyTableAndNotEmptyTable();break;}case 8: {ExitProgramm();break;}default:break;}
}void PrintEmptyTableAndNotEmptyTable()
{// 空闲表cout << "***********空闲表信息***********" << "\n起始地址\t空闲区大小" << endl;for (auto it = listEmptyArea.begin(); it != listEmptyArea.end(); ++it)if (it->size_of_empty != 0)it->PrintInfo();// 已分配内存表(进程表)listProcess.sort();cout << "***********非空闲表信息***********" << "\n进程id\t起始地址\t已分配大小" << endl;for (auto it = listProcess.begin(); it != listProcess.end(); ++it)if (it->size_of_process != 0)it->PrintInfo();
}void ExitProgramm()
{exit(0);
}void ScanfProgramm()
{cout << "输入进程ID <0 ~ 255>,占用空间大小<1 ~ 10>" << endl;cin >> inputId >> inputSize; // inputId inputSizeif (inputId > 255 || inputId < 0 || inputSize < 0 || inputSize > 10) {cout << "请输入范围内的值" << endl;ScanfProgramm();}for (auto it = listProcess.begin(); it != listProcess.end(); ++it) {if (it->process_id == inputId && it->size_of_process != 0) {cout << "进程的id号不能相同" << endl;ScanfProgramm();}}
}

内存的分配和回收实验(首次适配、下次适配、最佳适配、最坏适配)相关推荐

  1. 内存的分配与回收实验

    内存的分配与回收 北京师范大学珠海分校 实验目的 1.通过使用位图或空闲表,跟踪内存使用情况,模拟和评价不同的内存分配算法: 2.熟悉内存分配和回收管理过程. 实验要求 1.要求用你熟悉的程序设计语言 ...

  2. 可变分区存储管理实验报告总结_可变分区存储管理方式的内存分配和回收实验报告...

    操作系统实验报告 一.实验目的 通过编写和调试存储管理的模拟程序以加深对存储管理方案的理解,熟悉可变分区存储 管理的内存分配和回收. 二.实验内容 1.确定内存空间分配表: 2.采用最优适应算法完成内 ...

  3. 内存管理:内存的分配与回收

    内存管理:内存的分配与回收 1 内存的分配与回收 1.1 连续分配 1.1.1 单一连续分配 1.1.2 固定分区分配 1.1.3 动态分区分配 1.2 非连续分配 1.2.1 分段存储管理 1.2. ...

  4. 操作系统 内存的分配与回收

                                         操作系统 内存的分配与回收 无论什么进程,想要运行的就需要申请内存的空间,操作系统把我们的内存空间分割成化成一个个页表, 现在 ...

  5. 操作系统 -- 内存管理(分配与回收)

    目录 内存的分配方式 连续内存分配 单一连续分配(过时) 固态分区分配 动态分区分配 动态分区分配算法 首次适应算法 最佳适应算法 最坏适应算法 邻近适应算法 非连续内存分配 基础定义 地址转换 十进 ...

  6. 操作系统内存管理之内存的分配和回收

    分配与回收的目的 内存分配的过程 单一连续分配(已经过时) 固定分区分配 动态分区分配 动态分区空闲表数据结构:0-没有使用,1-使用了 动态分区空闲链数据结构:连续的合并在一起,这样可以减少空闲链表 ...

  7. 动态内存管理(内存的分配与回收)详解

    ** 1. 数据结构之动态内存管理机制 ** 通过前面的学习,介绍很多具体的数据结构的存储以及遍历的方式,过程中只是很表面地介绍了数据的存储,而没有涉及到更底层的有关的存储空间的分配与回收,从本节开始 ...

  8. 3.1.4 操作系统之内存的分配与回收

    文章目录 0.思维导图 1.单一连续分配 2.固定分区分配 (1)分区说明表 3.动态分区分配(可变分区分配) (1)系统要用怎样的数据结构记录内存的使用情况呢? (2)当多个空闲分区都能满足要求时, ...

  9. Linux中动态内存的分配与回收(heap, buddy system, stab)

    1.malloc 和free的原理(http://m.blog.csdn.net/article/details?id=39496057) 从操作系统角度来看,进程分配内存有两种方式,分别由两个系统调 ...

最新文章

  1. linux同步到对象存储,将Cpanel备份配置为S3对象存储的方法
  2. 提高工作效率:15个有用的项目管理工具
  3. uoj 118 赴京赶考
  4. R语言:cbind()和rbind()
  5. getopt实现传参自动识别
  6. 简单扩展shiro 实现NOT、AND、OR权限验证(支持复杂一点的表达式)
  7. java满天星星代码_满天星空的代码实现
  8. 嵌入式linux应用程序开发详解_【精品套餐】嵌入式linux应用驱动开发完全学习路线...
  9. odoo 自定义视图_如何使用Windows的五个模板自定义文件夹视图
  10. Eclipse集成svn后出现Failed to load JavaHL Library的解决办法
  11. java中super关键字的用法
  12. Flutter State生命周期 Flutter Widget生命周期 Flutter 应用程序生命周期
  13. php 流量,PHP 流量控制语句的顶替语法
  14. .net core精彩实例分享 -- LINQ
  15. 链表——【线性表(二)】
  16. html5 画布保存,html5 (canvas)画布save()和restore()的理解和使用方法
  17. 工作没做好,别人指出时最好装聋作哑
  18. 商业洞察力_正在进行的寻求洞察力和远见卓识
  19. pycharm如何更换背景图片
  20. sql update

热门文章

  1. java 管理 程序设计_用java编程设置管理的用户登录
  2. 用Bootstrap实现mansory网格瀑布流布局插件
  3. 秦智杂志秦智杂志社秦智编辑部2022年第12期目录
  4. 微信支付 SpringCloud+Vue
  5. 如何设计全面的客户端功能测试用例
  6. 利用百度地图采集大量某一区域经纬度信息
  7. Week 5: Management of the Sporadic Nature of Data Flows 4 - UE-Triggered Service Request
  8. CodeChef Squirrel and chestnut 题解
  9. 数字图像处理,图像的伪彩色处理
  10. 用于宏观经济数据分析的神经网络(Matlab代码实现)