第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(