3种页面置换算法 和3种内存动态分区分配方式
TIPS:键盘按下(CTRL+C,CTRL+V)开启白嫖模式
一、三种页面置换算法
#include<iostream> #include<fstream> using namespace std; //定义结构体模拟各存储块 typedef struct memoryblock { int number; //保存页面号 int time; //存储访问时间间隔 }block; int pagenum; //系统分配给作业的主存中的页面数 int memorynum; //可用内存页面数 int opt_missnum, fifo_missnum, lru_missnum; //各算法的缺页次数 float opt_missrate, fifo_missrate, lru_missrate; //各算法的缺页率 int curmemory; //当前页面标记变量 block *page; block *memory; //打印当前存储块中的内容 void print(block *memory) { for (int i = 0; i < memorynum; i++) printf("%2d ", memory[i].number); //打印块号 printf("\n"); } //查找当前存储块中是否包含待插入页面 int contains(int num, block *memory) { for (int i = 0; i < memorynum; i++) { if (num == memory[i].number) return i; //存储块中存在页面,返回页面位置 } return -1; //未找到 } //最优算法OPT //从内存中移出以后不再使用的页面;如没有这样的页面,选择以后最长时间内不需要访问的页面 //仅作为一种评价标准 void OPT() { opt_missnum = 0; int curmemory = 0; printf("*-----------------------------------------*\n"); printf("| 最优置换算法(max_disdis)置换情况: |\n"); printf("*-----------------------------------------*\n"); for (int i = 0; i < pagenum; i++) { if (contains(page[i].number, memory) >= 0) //内存块中有不缺页 { printf("%2d>", page[i].number); cout << " 不缺页" << endl; } else { int dis; //记录距离即未来的时间远近 int max_dis = 0; for (int j = 0; j < memorynum; j++) //找未来最久不需要访问的页面 { if (memory[j].number == -1) //先找空位置 { curmemory = j; break; } dis = 0; int k; for (k = i + 1; k < pagenum; k++) //在当前待进入页面之后走向中查找 { if (page[k].number == memory[j].number) //如果在存在未进入页面中出现已存在页面 { if (dis > max_dis) //找未来最久,也就是匹配时距离最长的 { max_dis = dis; curmemory = j; } break; //继续下一个查找 } else dis++; //两个相等页面的距离差距 } if (k == pagenum) //在未来未找到一个匹配的页面 { max_dis = dis; curmemory = j; //替换该孤独页面 } } opt_missnum++; memory[curmemory].number = page[i].number; //替换当前位置的页面 printf("%2d> ", page[i].number); print(memory); } } opt_missrate = (float)opt_missnum / pagenum; //求缺页率 printf("缺页次数:%d 缺页率: %f\n", opt_missnum, opt_missrate); } //先进先出算法FIFO //总是先淘汰那些驻留在内存时间最长的页面,即先进入的内存的页面先被置换掉 //最先进入内存的页面不再被访问的可能性最大 void FIFO() { fifo_missnum = 0; printf("*-----------------------------------------*\n"); printf("| 先进先出算法(FIFO)置换情况: |\n"); printf("*-----------------------------------------*\n"); for (int i = 0; i < pagenum; i++) //扫描待插入页面 { if (contains(page[i].number, memory) >= 0) //包含此页面 { printf("%2d>", page[i].number); cout << " 不缺页" << endl; //不缺页 } else { fifo_missnum++; //未找到说明缺页 memory[curmemory].number = page[i].number; //新的页面将最早进入的页面置换 printf("%2d> ", page[i].number); print(memory); curmemory = (curmemory + 1) % memorynum; //最早进入的页面变为置换掉的下一个 } } fifo_missrate = (float)fifo_missnum / pagenum; //求缺页率 printf("缺页次数:%d 缺页率: %f\n", fifo_missnum, fifo_missrate); } //最近最久未使用算法LRU //当需要置换一页时,选择最近一段时间最久未使用的页面予以淘汰 //如果某页很长时间没有被访问,那么最近也不太可能会被访问 void LRU() { lru_missnum = 0; int curmemory = 0; printf("*-----------------------------------------*\n"); printf("| 最近最久未使用算法(LRU)置换情况: |\n"); printf("*-----------------------------------------*\n"); for (int i = 0; i < pagenum; i++) { int t = contains(page[i].number, memory); //扫描待插入页面返回 if (t >= 0) //不缺页返回页面位置 { memory[t].time = 0; //发生访问时间间隔清0 printf("%2d>", page[i].number); cout << " 不缺页" << endl; } if (t < 0) //缺页,置换掉最近最久未使用的页面 { lru_missnum++; for (int j = 0; j < memorynum; j++) //找出最近最久未使用的页面 { if (memory[j].time == -1) //找到第一个从未被访问过的页面 { curmemory = j; //保存位置 break; } else if (memory[j].time > memory[curmemory].time) //没有空的位置就找目前呆在内存块中时间最长的那一块 curmemory = j; } memory[curmemory].number = page[i].number; //替换指定位置的页面 memory[curmemory].time = 0; //此时的页面刚被替换为新的,时间间隔变为0,表示新访问过重新计数 printf("%2d> ", page[i].number); print(memory); } for (int j = 0; j < memorynum; j++) //扫描此时所有的内存块中的页面 if (memory[j].number != -1) //把所有不是空的内存块位置上的时间长度增加 memory[j].time++; } lru_missrate = (float)lru_missnum / pagenum; //求缺页率 printf("缺页次数:%d 缺页率: %f\n", lru_missnum, lru_missrate); } //分别比较三种算法的缺页次数和缺页率 void COMP() { printf("*-----------------------------------------*\n"); printf("| 三种置换算法比较: |\n"); printf("*-----------------------------------------*\n"); printf("最优置换算法(OPT)置换情况: "); printf("缺页次数:%d 缺页率: %f\n", opt_missnum, opt_missrate); printf("先进先出算法(FIFO)置换情况: "); printf("缺页次数:%d 缺页率: %f\n", fifo_missnum, fifo_missrate); printf("最近最久未使用算法(LRU)置换情况: "); printf("缺页次数:%d 缺页率: %f\n", lru_missnum, lru_missrate); } //主函数 int main() { int op; cout << "输入系统分配给作业的主存中的页面数:" << endl; cout << ">> "; cin >> pagenum; page = (block*)malloc(sizeof(block)*pagenum); //创建页面存储结构体 cout << "输入内存页面存储块数:" << endl; cout << ">> "; cin >> memorynum; memory = (block*)malloc(sizeof(block)*memorynum); //创建内存页面存储结构体 cout << "文件输入各页面走向:" << endl; int datalen = 0; ifstream file("b.txt"); while (!file.eof()) file >> page[datalen++].number; //输入页面走向 cout << ">> "; for (int i = 0; i < datalen; i++) { cout << page[i].number << " "; page[i].time = 0; //访问次数全置0 } do { for (int i = 0; i < memorynum; i++) { memory[i].number = -1; memory[i].time = -1; //初始化存储块 } printf("\n*--------------------------------------------*\n"); printf("| 页面置换算法模拟 |\n"); printf("*--------------------------------------------*\n"); printf("| 1) 最优置换算法(OPT) |\n"); printf("| 2) 先进先出算法(FIFO) |\n"); printf("| 3) 最近最久未使用算法(LRU) |\n"); printf("| 4) 三种算法比较 |\n"); printf("| 0) 退出 |\n"); printf("*--------------------------------------------*\n\n"); cout << ">> "; cin >> op; system("cls"); if (op == 1) OPT(); else if (op == 2) FIFO(); else if (op == 3) LRU(); else if (op == 4) COMP(); } while (op != 0); }
二、3种内存动态分区分配方式
#include<iostream> #include<stdlib.h> using namespace std; constexpr auto MEMORY_SIZE = 640; //初始内存大小设置为640KB constexpr auto ALLOCED = 1; //占用设为1 constexpr auto FREE = 0; //未被占用/释放空闲分区为0 typedef struct SubAreaNode *SubAreaList; struct SubAreaNode { int addr; //分区起始地址 int size; //分区大小 int start; //分区状态 宏定义 ALLOCED 1 FREE 0 int pid; //已分配分区的进程id,未分配id设为-1 SubAreaList pre; //前驱节点 SubAreaList next; //后一节点 }; SubAreaList head; //设置全局变量,分区链表头指针 //为分区链表指针分配内存空间 SubAreaList getASubArea() { return (SubAreaList)malloc(sizeof(struct SubAreaNode)); } //对空闲分区链表进行初始化,一整块空间为空 SubAreaList initSubArea() { SubAreaList p = getASubArea(); p->addr = 0; //头指针的位置为0 p->size = MEMORY_SIZE; //内存大小为规定大小 p->start = FREE; //初始分区状态是未占用 p->pid = -1; //未分配id置为-1 p->pre = NULL; //头指针前驱结点为空 p->next = NULL; //头指针后一节点为空 return p; //返回初始化的头指针 } //分区分配算法,为链表p处标号为pid,大小为psize 的作业分配空间 int alloc(int pid, int psize, SubAreaList p) { if (p == NULL) return 0; if (p->size == psize) //进程大小与待分配分区大小相同 { p->start = ALLOCED; //分区被占用 p->pid = pid; //修改分区编号 } else //进程大小小于待分配区域 { SubAreaList newSubArea = getASubArea(); //分割内存区域 newSubArea->addr = p->addr + psize; //新分区起始位置为已分配的加分配区大小 newSubArea->size = p->size - psize; //新分区大小为原分区大小减去已分配内存 newSubArea->start = FREE; //新分区置未被占用 newSubArea->pid = -1; //初始化分区号 p->size = psize; //原分区分配大小 p->start = ALLOCED; //原分区被占用 p->pid = pid; //设置原分区编号 newSubArea->next = p->next; //在原分区后面插入新分割的分区 p->next = newSubArea; //指针移动 newSubArea->pre = p; } return 1; //成功分配返回1 } //回收分区算法,回收分区号为pid的分区 int freeAlloc(int pid) { SubAreaList p = head; //p指向头指针 while (p) { if (p->pid == pid) break; p = p->next; //先找到分区号为pid的位置 } if (p == NULL) return 0; //未找到 if (p != head && p->pre->start == FREE && p->pre->addr + p->pre->size == p->addr) {//如果p不是头指针且p的前一个分区是空闲的并且p和前一个分区是相连的那么将待回收分区和前一分区合并实现回收 SubAreaList preNode = p->pre; SubAreaList nextNode = p->next; preNode->size += p->size; //前一分区的大小扩大 preNode->next = p->next; //前一分区的下一分区变为回收分区的下一分区 nextNode->pre = preNode; //回收分区的前一分区变为回收分区的前一分区 if (p->next->start == FREE && p->addr + p->size == p->next->addr) {//如果此时后一分区也是空闲的并且此时的待回收分区和后一分区也相邻那么将待回收分区和后一分区合并实现回收 preNode->size += nextNode->size; //继续扩大前一分区的大小 preNode->next = nextNode->next; //前一分区的下一分区变为回收分区的下一分区的下一分区 preNode->next->pre = preNode; //回收分区的下一分区的前一分区变为回收分区的前一分区 free(nextNode); //释放下一分区节点 } free(p); //释放回收分区节点 } else { if (p->next != NULL && p->next->start == FREE && p->addr + p->size == p->next->addr) {//如果不是最后一个分区并且后面的一个分区是空闲的但是前面的分区不空闲就将待回收分区和后一分区合并 SubAreaList nextNode = p->next; p->size += nextNode->size; //待回收分区大小扩大 p->next = nextNode->next; //待回收分区的下一分区变为下一分区的下一分区 nextNode->next->pre = p; //下一分区的前一分区变为待回收分区 p->start = FREE; //待回收分区置空闲 p->pid = -1; //回收分区号 free(nextNode); //释放下一分区节点 } else { p->start = FREE; //如果是前后都不空或者最后一个分区直接置空闲 p->pid = -1; //回收分区号 } } return -1; //回收失败 } //首次适应算法,从分区链表中找到第一个不小于psize的空闲分区,返回此分区地址。 //如果找不到可用的空闲分区返回NULL。 SubAreaList ffFindFreeSubArea(int psize) { SubAreaList p = head; while (p) { //从头结点开始 if (p->start == FREE && p->size >= psize) return p; //未被占用且大小合适返回指针 p = p->next; //未找到移动指针 } return NULL; //分配失败 } int ffAlloc(int pid, int psize) { return alloc(pid, psize, ffFindFreeSubArea(psize)); //如果查找成功返回指针并根据指针分配并修改空间 } //最佳适应算法,空闲分区按照大小升序排列,从头寻找第一个符合要求的空间分区进行分配。 //如果找不到可用的空闲分区返回NULL。 SubAreaList bfFindFreeSubArea(int psize) { SubAreaList p = head, minP = NULL; int minSize = MEMORY_SIZE + 1; while (p) //每次查找都找最小的且满足空间大小的 { if (p->start == FREE && p->size >= psize) { if (p->size < minSize) { minSize = p->size; //查找最小的空闲分区 minP = p; //保存满足要求的最小分区的指针位置 } } p = p->next; } return minP; //返回指针位置 } int bfAlloc(int pid, int psize) { return alloc(pid, psize, bfFindFreeSubArea(psize)); //如果查找成功返回指针并根据指针分配并修改空间 } //最坏适应算法,空闲分区按照大小降序排列,从头寻找第一个符合要求的空间分区进行分配。 //如果找不到可用的空闲分区返回NULL。 SubAreaList wfFindFreeSubArea(int psize) { SubAreaList p = head, maxP = NULL; int maxSize = -1; //每次查找都找最大的且满足空间大小的 while (p) { if (p->start == FREE && p->size >= psize) { if (p->size > maxSize) { maxSize = p->size; //查找最大的空闲分区 maxP = p; //保存满足要求的最大分区的指针位置 } } p = p->next; } return maxP; //返回指针位置 } int wfAlloc(int pid, int psize) { return alloc(pid, psize, wfFindFreeSubArea(psize));//如果查找成功返回指针并根据指针分配并修改空间 } //打印分配存储区情况,并显示分区状态及相关信息 void displayAlloc() { SubAreaList p = head; printf("\n%3s %3s %3s %3s %3s\n", "ID", "起始", "终止", "长度", "状态"); while (p) //打印分区链表的所有有效内容 { printf("%3d %3d %3d %3d", p->pid, p->addr, p->addr + p->size - 1, p->size); if (p->start == 1) printf(" 已分配\n"); else printf(" 空闲\n"); p = p->next; } printf("\n"); } //输入控制 void inputCtrl(int(*allocAlogrithm)(int, int)) { printf("分配输入: A 作业号 大小\n"); printf("回收输入: F 作业号\n"); printf("退出输入: Q\n\n"); char t[5]; cin >> t; while (t[0] != 'Q') { if (t[0] == 'A') { int pid, size; cin >> pid >> size; //给作业号为pid的大小为size的作业分配空间 int ret = allocAlogrithm(pid, size); //分配是否成功判断 if (ret) { printf("作业号 %d 分配 %d KB\n", pid, size); displayAlloc(); //成功分配输出分配结果 } else { printf("\n内存不足 分配失败\n\n"); } } else if (t[0] == 'F') //释放分区 { int pid; cin >> pid; int ret = freeAlloc(pid); //调用回收算法 if (ret) { printf("作业号 %d 已回收\n", pid); displayAlloc(); //成功分配输出分配结果 } else printf("未找到相关作业,回收失败\n\n"); } else exit(0); cin >> t; //未退出时一直输出 } } //从文件中读入相关操作 void fileInputCtrl(int(*allocAlogrithm)(int, int)) { FILE *stream1; freopen_s(&stream1, "a.txt", "r", stdin); //打开文件重定向控制台输入 inputCtrl(allocAlogrithm); //输入数据进入输入控制 freopen_s(&stream1, "CON", "r", stdin); //恢复控制台输入 } //首次适应算法界面 void ffAllocCtrl() { system("cls"); printf("\n*--------------------------------------------*\n"); printf("| 首次适应算法 |\n"); printf("*--------------------------------------------*\n"); printf("| 1) 输入请求序列 |\n"); printf("| 2) 文件输入请求序列 |\n"); printf("| q) 退出 |\n"); printf("*--------------------------------------------*\n\n"); int op; printf(">> "); cin >> op; if (op == 1) inputCtrl(ffAlloc); else if (op == 2) fileInputCtrl(ffAlloc); else exit(0); } //最佳适应算法界面 void bfAllocCtrl() { system("cls"); printf("\n*--------------------------------------------*\n"); printf("| 最佳适应算法 |\n"); printf("*--------------------------------------------*\n"); printf("| 1) 输入请求序列 |\n"); printf("| 2) 文件输入请求序列 |\n"); printf("| q) 退出 |\n"); printf("*--------------------------------------------*\n\n"); int op; printf(">> "); cin >> op; if (op == 1) inputCtrl(bfAlloc); else if (op == 2) fileInputCtrl(bfAlloc); else exit(0); } //最坏适应算法界面 void wfAllocCtrl() { system("cls"); printf("\n*--------------------------------------------*\n"); printf("| 最坏适应算法 |\n"); printf("*--------------------------------------------*\n"); printf("| 1) 输入请求序列 |\n"); printf("| 2) 文件输入请求序列 |\n"); printf("| q) 退出 |\n"); printf("*--------------------------------------------*\n\n"); int op; printf(">> "); cin >> op; if (op == 1) inputCtrl(wfAlloc); else if (op == 2) fileInputCtrl(wfAlloc); else exit(0); } //主界面选择各适应算法 void selectAlogrithm() { system("cls"); printf("\n*--------------------------------------------*\n"); printf("| 内存动态分区分配方式的模拟 |\n"); printf("*--------------------------------------------*\n"); printf("| 1) 首次适应算法 |\n"); printf("| 2) 最佳适应算法 |\n"); printf("| 3) 最坏适应算法 |\n"); printf("| 0) 退出 |\n"); printf("*--------------------------------------------*\n\n"); int op; printf(">> "); cin >> op; if (op == 1) ffAllocCtrl(); else if (op == 2) bfAllocCtrl(); else if (op == 3) wfAllocCtrl(); else exit(0); } //主函数 int main() { head = initSubArea(); //初始化分区链表 selectAlogrithm(); //选择算法主界面 return 0; }