赞
踩
编写一个 C程序模拟实现请求页面置换算法,包括FIFO、LRU (stack and matrix implementation)、Secondchance,并设计输入用例验证结果。
在计算机操作系统使用分页的虚拟内存管理,页面置换算法决定哪些内存页页出,有时也被称为换出,或写入到磁盘上,当一个页面被分配的内存需求。当请求的页面不在内存中(页面错误)并且空闲页面无法用于满足分配时,就会发生页面替换,要么是因为没有页面,要么是因为空闲页面的数量低于某个阈值。
使用isNeedReplace
来标记是否需要进行置换,使用pointer
来指向下一个页表号应该存放的地方,
对于想要访问的每一个页面,首先先判断是否需要进行置换,通过依次遍历内存数组,
isNeedReplace
为0,表示不需要进行置换,并打印该页面命中并跳出循环isNeedReplace
为0,表示不需要进行置换,接着打印该页面缺失并跳出循环。接着通过判断isNeedReplace
是否为1来判断是否需要进行页面的替换,为1则表示该页表没有存在于内存中且内存中没有空位使其直接插入,页面替代队列的头结点,即pointer
所指向的点,pointer
++,因为程序使用的是循环队列,因此当pointer到达最后一个队列位置之后时,需要重新设置其指向队列的第一个位置,接着打印该页面缺失。
/*先进先出置换算法FIFO*/ void replaceAlgFIFO(){ int pointer = 0;//指向下一个页表号应该存放的地方 int isNeedReplace = 1;//是否需要进行页面置换,如果内存中没有该页表号且内存已满,则需要,为1 for (int i = 0; i < pageNum; i ++) { isNeedReplace = 1; //判断是否需要置换,内存已满且该页面不在内存中,则需要 for (int j = 0; j < phyBlockNum; j ++) { if (memList[j] == pageToVisit[i]) { isNeedReplace = 0;//该页面在内存中,不需要进行页面置换 printf("%d hit\n",pageToVisit[i]);//命中 break; } if (memList[j] == -1) {//页面不在内存中且内存未满 memList[j] = pageToVisit[i]; isNeedReplace = 0;//内存未满,不需要进行页面置换 printf("%d miss\n",pageToVisit[i]);//缺失 printList(); break; } } if (isNeedReplace) {//需要进行页面置换 //如果pointer指向最后一个之后的区域,则归零 if (pointer > phyBlockNum-1) pointer = 0; memList[pointer] = pageToVisit[i];//按照FIFO的原则替代pointer所指的节点 pointer ++; printf("%d miss\n",pageToVisit[i]);//缺失 printList(); } } }
使用isNeedReplace
来标记是否需要进行置换,使用count
来表示当前在内存中的页面数量,
对于想要访问的每一个页面,首先先判断是否需要进行置换,通过依次遍历内存数组,
isNeedReplace
为0,表示不需要进行置换,最后打印该页面命中并跳出循环isNeedReplace
为0,表示不需要进行置换,接着将count+1,表示当前在内存中的页面数量增加一个,最后打印该页面缺失并跳出循环。接着通过判断isNeedReplace
是否为1来判断是否需要进行页面的替换,为1则表示该页表没有存在于内存中且内存中没有空位使其直接插入,将数组整体往前移一位,过程中队列队头(栈头)弹出,在队列的结尾加上该页面作为新节点,接着打印该页面缺失。
/*最近最久未使用置换算法LRU-stack实现*/ void replaceAlgStackLRU(){ int isNeedReplace = 1;//是否需要进行页面置换,如果内存中没有该页表号且内存已满,则需要,为1 int count = 0;//在内存中的页面数量 for (int i = 0; i < pageNum; i ++) { isNeedReplace = 1; //判断是否需要置换,内存已满且该页面不在内存中,则需要 for (int j = 0; j < phyBlockNum; j ++) { if (memList[j] == pageToVisit[i]) { //已经存在于内存中,把它换到队列尾部 int temp = memList[j]; for (int k = j; k < count-1; k ++) { memList[k] = memList[k+1]; } memList[count-1] = temp; isNeedReplace = 0;//该页面在内存中,不需要进行页面置换 printf("%d hit\n",pageToVisit[i]);//命中 printList(); break; } if (memList[j] == -1) {//页面不在内存中且内存未满 memList[j] = pageToVisit[i]; isNeedReplace = 0;//内存未满,不需要进行页面置换 count ++; printf("%d miss\n",pageToVisit[i]); printList(); break; } } if (isNeedReplace) {//需要进行页面置换 //将数组整体往前移一位 for (int k = 0; k < phyBlockNum; k ++) { memList[k] = memList[k+1]; } //将当前页面加到队尾 memList[phyBlockNum-1] = pageToVisit[i]; printf("%d miss\n",pageToVisit[i]); printList(); } } }
用矩阵的方法来实现LRU算法的思想是使用矩阵来记录页面使用的频率和时间。设矩阵是n×n维的,n是相关程序当前驻内存的页面数。矩阵的初值为0,每次访问一个页面,例如第i个虛拟页被访问时,可对矩阵进行如下操作:
在每次需要更换页面时,选择矩阵里对应行值最小的页面淘汰
,该页面及时最近最少使用的页面。原理如下:
使用Matrix
来记录页面使用的频率和时间,其功能在上述介绍中已经详细介绍,先对其中的全部元素初始化为0,使用isNeedReplace
来标记是否需要进行置换,使用count
来表示当前在内存中的页面数量,对于想要访问的每一个页面,首先该页面所对应的行值将被置1,这样就保证了该页面对应的行值为最大之一,随后将该页面的对应列值置0,以保证该页面对应的行值为唯一最大。
然后再判断是否需要进行置换,通过依次遍历内存数组,
isNeedReplace
为0,表示不需要进行置换,然后打印该页面命中并跳出循环isNeedReplace
为0,表示不需要进行置换,接着将count+1,表示当前在内存中的页面数量增加一个,最后打印该页面缺失并跳出循环。接着通过判断isNeedReplace
是否为1来判断是否需要进行页面的替换,为1则表示该页表没有存在于内存中且内存中没有空位使其直接插入,遍历矩阵中在内存快中存在的页面的行,寻找行的零数最多的即为最久未访问的页面所在的内存下标,将下标对应的队列中的节点替换成该页面,接着打印该页面缺失。
//最近最久未使用置换算法LRU-矩阵实现 void replaceAlgMatrixLRU(){ //矩阵,用来记录节点最近最久未被使用的程度大小 int Matrix[pageNum][pageNum]; //初始化矩阵 for(int i=0;i<pageNum;i++){ for(int j=0;j<pageNum;j++) Matrix[i][j]=0; } int isNeedReplace = 1;//是否需要进行页面置换,如果内存中没有该页表号且内存已满,则需要,为1 int count = 0;//在内存中的页面数量 for (int i = 0; i < pageNum; i ++) { isNeedReplace = 1; //pageToVisit[i]行置1,pageToVisit[i]列置0 for (int p = 0; p < pageNum; p ++) { Matrix[pageToVisit[i]][p]=1; } for (int p = 0; p < pageNum; p ++) { Matrix[p][pageToVisit[i]]=0; } //判断是否需要置换,内存已满且该页面不在内存中,则需要 for (int j = 0; j < phyBlockNum; j ++) { if (memList[j] == pageToVisit[i]) { isNeedReplace = 0;//该页面在内存中,不需要进行页面置换 printf("%d hit\n",pageToVisit[i]);//命中 break; } if (memList[j] == -1) {//页面不在内存中且内存未满 memList[j] = pageToVisit[i]; count ++;//在内存中的页面数量+1 isNeedReplace = 0;//内存未满,不需要进行页面置换 printf("%d miss\n",pageToVisit[i]);//缺失 printList(); break; } } if (isNeedReplace) {//需要进行页面置换 //遍历矩阵中在内存快中存在的页面的行,寻找行的零数最多的即为最久未访问的页面所在的内存下标 int max = 0;//记录内存块中的页面对应到矩阵中的行的零数总和最大的节点 int sum[phyBlockNum];//记录内存块中的页面对应到矩阵中的行的零数总和 //找出max节点,即最近最久未使用的页面 for (int k = 0; k < phyBlockNum; k ++) { sum[k]=0; for(int p=0;p<pageNum;p++){ if(Matrix[memList[k]][p]==0)sum[k]+=1; } if(sum[k]>sum[max]){ max=k; } } memList[max] = pageToVisit[i];//替换掉最近最久未使用的页面 printf("%d miss\n",pageToVisit[i]);//缺失 printList(); } } }
该算法仍然使用标准的FIFO队列。
每个帧(frame)有一个second chance位,也叫做引用位。
如果一个页面被频繁使用以保持其引用
位设置,它永远不会被替换。
使用secondChance
数组来记录内存中的页表是否有不被替换出去的机会,其功能在上述介绍中已经详细介绍,先对其中的全部元素初始化为0,使用isNeedReplace
来标记是否需要进行置换,使用pointer
来指向下一个页表号应该存放的地方,使用count
来表示当前在内存中的页面数量。
对于想要访问的每一个页面,首先判断是否需要进行置换,通过依次遍历内存数组,
isNeedReplace
为0,表示不需要进行置换,并设置该页表的secondChance为1,表示该页表在下一次将要被替换时,有不被替换出去的机会,然后打印该页面命中并跳出循环isNeedReplace
为0,表示不需要进行置换,接着将count+1,表示当前在内存中的页面数量增加一个,最后打印该页面缺失并跳出循环。接着通过判断isNeedReplace
是否为1来判断是否需要进行页面的替换,为1则表示该页表没有存在于内存中且内存中没有空位使其直接插入,先判断当前要替换的页面(pointer指向的页面)是否有不被替换出去的机会,即其对应的secondChange的值是否为一,如果为1则修改其为0并且将point加一,循环这个过程知道找到secondChange不为1的节点,将该节点替换成访问的页面,接着打印该页面缺失。
/*二次机会算法SCR*/ void replaceAlgSecondchance(){ //记录内存中的页表是否有不被替换出去的机会 int secondChance[phyBlockNum]; //初始化 for(int i=0;i<phyBlockNum;i++){ secondChance[i]=0; } int isNeedReplace = 0;//是否需要进行页面置换,如果内存中没有该页表号且内存已满,则需要,为1 int pointer=0;//指向下一个页表号应该存放的地方 int count = 0;//在内存中的页面数量 for (int i = 0; i < pageNum; i ++) { isNeedReplace = 1; //判断是否需要置换,内存已满且该页面不在内存中,则需要 for (int j = 0; j < phyBlockNum; j ++) { if (memList[j] == pageToVisit[i]) { isNeedReplace = 0;//该页面在内存中,不需要进行页面置换 //设置被访问过的内存中的页表有不被替换出去的机会 secondChance[j] = 1; printf("%d hit\n",pageToVisit[i]); break; } if (memList[j] == -1) {//页面不在内存中且内存未满 memList[j] = pageToVisit[i]; count ++; secondChance[j] = 1;//首先被加入的位 isNeedReplace = 0;//内存未满,不需要进行页面置换 printf("%d miss\n",pageToVisit[i]); printList(); break; } } if (isNeedReplace) {//需要进行页面置换 //如果point指向的节点在这一轮有不被替换出去的机会,则point++,判断下一个是否需要被替换出去 while(secondChance[pointer]==1){ secondChance[pointer]=0; pointer++; if (pointer > phyBlockNum-1) { pointer = 0; } } if (pointer > phyBlockNum-1) { pointer = 0; } memList[pointer] = pageToVisit[i]; pointer ++; printf("%d miss\n",pageToVisit[i]); printList(); } } }
程序一开始要求输入置换算法类型strategy
,物理块数量phyBlockNum
,准备访问的页面总数pageNum
,然后输入pageNum
数量的待访问的页面号,再根据strategy
选择进入置换算法函数(在上述有提到)进行依次的置换。
按照要求选择FIFO算法,使用课件上的样例,选择3块物理块,输入20次要访问页面的次数,并依次输入每一次要访问的页面编号,如下图所示:
执行结果如下:
和课本中的结果一致,如下,都满足先进先出的原则:
按照要求选择LRU(stack)算法,使用课件上的样例,选择5块物理块,输入13次要访问页面的次数,并依次输入每一次要访问的页面编号,如下图所示:
执行结果如下:
和课本中的结果基本一致(程序将下面作为栈的头部或队列的尾部,而课件中将上面作为栈的头部或队列的尾部),都满足LRU的原则:
按照要求选择LRU(matrix)算法,使用课件上的样例,选择3块物理块,输入12次要访问页面的次数,并依次输入每一次要访问的页面编号,如下图所示:
执行结果如下:
和课本中的结果一致,都满足LRU的原则:
按照要求选择LRU(matrix)算法,使用课件上的样例,选择3块物理块,输入12次要访问页面的次数,并依次输入每一次要访问的页面编号,如下图所示:
执行结果如下:
和课本中的结果基本一致,都满足secondChance的原则:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。