页面置换算法实验报告c语言(大一c语言课程设计计算器)

在进程运行过程中,如果它需要访问的页面不在内存,需要把它调入内存,但是内存已满时,需要把内存中的某页数据送到磁盘的对换区中。而选择哪个页面,则由固定的算法来决定,称为页面置换算法

大家好,又见面了,我是你们的朋友全栈君。

实验目的

1、了解内存分页管理策略

2、掌握一些基本的页面置换算法

实验内容与基本要求

用C,C++等语言编写程序,实现OPT、FIFO、LRU置换算法

页面置换算法的基本内容

页面置换算法是在当进程运行过程中,若其要访问的页面不在内存且内存已满时,要决定将哪个页面换出的算法。常见的页面置换算法包括最佳置换、先进先出置换、最近最久未使用置换和Clock置换等。本次的实验实现的算法包括最佳置换算法(OPT)、先进先出置换算法(FIFO)和最近最久未使用算法(LRU)。

页面置换算法涉及到一些概念如下:

  • 缺页率:当需要访问的页面不在内存时称为缺页,此时需要将页面调入内存。缺页率就是要访问的页面不在内存中的概率。因此缺页率=缺页次数/要访问的页面总数。需要注意的是,缺页的时候不一定需要进行页面置换(如果内存还没满,直接将页面调入内存即可)。
  • 置换率:置换就是将旧页面调出内存,新页面调进内存,即新页面代替旧页面的过程。置换率就是需要进行页面置换的概率。所以置换率=置换次数/要访问的页面总数。
  • 命中率:就是要访问的页面恰好在内存中的概率。可以发现(缺页率+命中率=1)。

最佳置换算法

最佳置换算法,就是所选择内存中以后永远不再使用,或者是在未来最长的一段时间内不再被访问的页面来换出。

img_1
用这种算法可以保证获得最低的缺页率,最低的置换次数,因此效率最高。然而在实际情况中,我们是无法知道哪个页面是未来最长时间内不再被访问的,所以实际上它是无法实现的。

先进先出置换算法

先进先出置换算法,就是选择内存中最先进入内存,在内存中呆的最久的页面来换出。它实现简单,但是效率不高。
img_2
img_3

最近最久未使用算法

最近最久未使用算法,是选择当前内存中,最久没有被访问的页面来换出。它是希望通过过去页面访问的情况,来预测未来页面的访问情况,但是页面过去与未来的走向之间并没有必然的联系,因此它的效率也不是十分高。
img_4
img_5

实现思路

无论采用哪个算法,当进程需要访问一个页面时,存在三种情况:

1.页面已经在内存中

2.页面不在内存中,但是此时内存还未满

3.页面不在内存中,且此时内存已满,需要把页面换出

不同算法的区别主要是决定换出哪个页面

img_6

最佳置换算法中,被换出的算法是在最长未来时间内不再被访问的页面。也就是说,需要计算出当前内存中页面的下一次访问位置,哪个页面的下一次访问位置最远,就将它换出。因此需要一个数组额外记录下次访问位置,每当访问完一个页面(不管这个页面是新换入的,还是早就在内存中的),都需要遍历剩下的页面号引用串,更新这个数组。

先进先出置换算法比较简单,用一个变量记录当前内存中最先进入页面的下标。由于页面都是按数组下标顺序保存的,因此每访问一个页面,该变量就加一。等变量等于数组长度时,再重新归零即可。

最近最久未使用算法有两种思路:1.与最佳置换算法类似,设置一个时间数组,记录从内存中页面上次访问至今的时间,哪个页面的时间最长则将它换出。如果要访问的页面已在内存中,则时间归零。当每次发起一个访问请求,则所有页面访问时间加一,更新该数组。2.用数组模拟队列的结构,队列头出队列尾入,每当需要访问新的页面时,就将数组内的数据前移一位,新页面加入数组最后。如果要访问的页面已在内存中,则用一个临时变量记录该页面,然后从该页面起的数据前移一位,把该页面加入数组最后(课本上说是用栈的结构,但是严格上来说,栈只允许一端出入。因此按照课本上的功能描述,实际应该采用的结构仍是队列)

流程图

程序总流程图

总流程图

OPT算法流程图

OPT

FIFO算法流程图

FIFO

LRU算法流程图

LRU

全部代码

代码

//
// main.c
// pageReplacement
//
// Created by Apple on 2019/11/12.
// Copyright © 2019 Yao YongXin. All rights reserved.
//

#include <stdio.h>

//初始化队列
void initializeList(int list[],int number){ 
   
    for (int i = 0; i < number; i ++) { 
   
        list[i] = -1;
    }
}
//展示队列状态
void showList(int list[], int number){ 
   
    for (int i = 0; i < number; i ++) { 
   
        printf("%2d",list[i]);
    }
    printf("\n");
}

//展示当前内存状态
void showMemoryList(int list[],int phyBlockNum){ 
   
    for (int i = 0; i < phyBlockNum; i ++) { 
   
        if (list[i] == -1) { 
   
            break;
        }
        printf(" |%d|",list[i]);
    }
    printf("\n");
}

void informationCount(int missingCount,int replaceCount,int pageNum){ 
   
    printf("缺页次数:%d 缺页率:%d/%d\n",missingCount,missingCount,pageNum);
    double result = (double)(pageNum - missingCount)/(double)pageNum;
    printf("置换次数:%d 命中率:%.2f\n",replaceCount,result);
}

//找到该页面下次要访问的位置
int getNextPosition(int currentPage,int currentPosition,int strList[],int pageNum){ 
   
    
    for (int i = currentPosition+1; i < pageNum; i ++) { 
   
        if (strList[i] == currentPage) { 
   
            return i;
        }
    }
    
    return 100;
}

//最佳置换算法
void replacePageByOPT(int memoryList[],int phyNum,int strList[],int pageNum){ 
   
    
    //置换次数
    int replaceCount = 0;
    //缺页次数
    int missingCount = 0;
    
    //记录在内存的物理块的下一次访问位置
    int nextPosition[phyNum];
    //初始化
    initializeList(nextPosition, phyNum);
    
    //记录当前页面的访问情况: 0 未访问
    int isVisited;
    
    for (int i = 0; i < pageNum; i ++) { 
   
        isVisited = 0;
        //判断是否需要置换->内存已满且需要访问的页面不在内存中
        for (int j = 0; j < phyNum; j ++) { 
   
            if (memoryList[j] == strList[i]) { 
   
                //该页面已经存在内存中
                //记录下一次访问它的位置
                nextPosition[j] = getNextPosition(memoryList[j], i, strList, pageNum);
                
                //修改访问情况
                isVisited = 1;
                
                //展示
                printf("%d\n",strList[i]);
                break;
            }
            if (memoryList[j] == -1) { 
   
                //页面不在内存中且内存未满->直接存入
                memoryList[j] = strList[i];
                nextPosition[j] = getNextPosition(memoryList[j], i, strList, pageNum);
                
                missingCount ++;
                
                //修改访问情况
                isVisited = 1;
                
                //展示
                printf("%d\n",strList[i]);
                showMemoryList(memoryList, phyNum);
                break;
            }
        }
        
        if (!isVisited) { 
   
            
            //当前页面还没访问过
            //内存已满且当前访问不在内存中->进行置换
            //1.寻找到最晚才被访问到的页面
            int max = 0;
            for (int k = 1; k < phyNum; k ++) { 
   
                if (nextPosition[max] < nextPosition[k]) { 
   
                    max = k;
                }
            }
            
            
            //2.将该位置的页面换出
            memoryList[max] = strList[i];
            nextPosition[max] = getNextPosition(memoryList[max], i, strList, pageNum);
            
            missingCount ++;
            replaceCount ++;
            
            //展示
            printf("%d\n",strList[i]);
            showMemoryList(memoryList, phyNum);
        }
    }
    informationCount(missingCount, replaceCount,pageNum);
}
//先进先出置换算法
void replacePageByFIFO(int memoryList[],int phyNum,int strList[],int pageNum){ 
   
    
    //置换次数
    int replaceCount = 0;
    //缺页次数
    int missingCount = 0;
    
    //记录当前最早进入内存的下标
    int pointer = 0;
    
    //记录当前页面的访问情况: 0 未访问
    int isVisited = 0;
    for (int i = 0; i < pageNum; i ++) { 
   
        isVisited = 0;
        
        //判断是否需要置换->内存已满且需要访问的页面不在内存中
        for (int j = 0; j < phyNum; j ++) { 
   
            if (memoryList[j] == strList[i]) { 
   
                //该页面已经存在内存中
                //修改访问情况
                isVisited = 1;
                //修改访问时间
                //展示
                printf("%d\n",strList[i]);
                break;
            }
            if (memoryList[j] == -1) { 
   
                //页面不在内存中且内存未满->直接存入
                memoryList[j] = strList[i];
                //修改访问情况
                isVisited = 1;
                missingCount ++;
                //展示
                printf("%d\n",strList[i]);
                showMemoryList(memoryList, phyNum);
                break;
            }
        }
        
        if (!isVisited) { 
   
            //当前页面还未被访问过->需要进行页面置换
            //直接把这个页面存到所记录的下标中
            memoryList[pointer] = strList[i];
            
            //下标指向下一个
            pointer ++;
            
            //如果到了最后一个,将下标归零
            if (pointer > phyNum-1) { 
   
                pointer = 0;
            }
            
            
            missingCount ++;
            replaceCount ++;
            
            //展示
            printf("%d\n",strList[i]);
            showMemoryList(memoryList, phyNum);
        }
    }
    informationCount(missingCount, replaceCount, pageNum);
}

//最近最久未使用置换算法
void replacePageByLRU(int memoryList[],int phyNum,int strList[],int pageNum){ 
   
    
    //置换次数
    int replaceCount = 0;
    //缺页次数
    int missingCount = 0;

    //记录内存中最近一次访问至今的时间
    int timeRecord[phyNum];
    //初始化
    initializeList(timeRecord, phyNum);

    //记录当前页面的访问情况: 0 未访问
    int isVisited = 0;
    
    //记录已经在内存中的页面数量
    int pageCount = 0;
    for (int i = 0; i < pageNum; i ++) { 
   
        isVisited = 0;
        
        //时间加一
        for (int p = 0; p < pageCount; p ++) { 
   
            if (memoryList[p] != -1) { 
   
                timeRecord[p] ++;
            }
        }
        
        //是否需要置换
        for (int j = 0; j < phyNum; j ++) { 
   
            if (memoryList[j] == strList[i]) { 
   
                //该页面已经存在内存中
                //修改访问情况
                isVisited = 1;
                //重置访问时间
                timeRecord[j] = -1;
                //展示
                printf("%d\n",strList[i]);
                break;
            }
            if (memoryList[j] == -1) { 
   
                //页面不在内存中且内存未满->直接存入
                memoryList[j] = strList[i];
                pageCount ++;
                //修改访问情况
                isVisited = 1;
                //修改访问时间
                timeRecord[j] ++;
                
                missingCount ++;
                //展示
                printf("%d\n",strList[i]);
                showMemoryList(memoryList, phyNum);
                break;
            }
        }

        if (!isVisited) { 
   
            //需要置换
            //1.遍历时间记录表,寻找最久未访问的页面所在的内存下标
            int max = 0;
            for (int k = 0; k < phyNum; k ++) { 
   
                if (timeRecord[max] < timeRecord[k]) { 
   
                    max = k;
                }
            }

            //2.将该位置的页面换出
            memoryList[max] = strList[i];
            timeRecord[max] = -1;
            
            missingCount ++;
            replaceCount ++;

            //展示
            printf("%d\n",strList[i]);
            showMemoryList(memoryList, phyNum);
            
        }
    }
    informationCount(missingCount, replaceCount, pageNum);
}

//最近最久未使用置换算法-2
//void replacePageByLRU(int memoryList[],int phyNum,int strList[],int pageNum){ 
   
//
// int isVisited = 0;
//
// //记录已经在内存中的页面数量
// int pageCount = 0;
// for (int i = 0; i < pageNum; i ++) { 
   
// isVisited = 0;
// //判断内存是否需要换页
// for (int j = 0; j < phyNum; j ++) { 
   
// if (memoryList[j] == strList[i]) { 
   
// //已经存在于内存中,把它换到队列尾部
// int temp = memoryList[j];
// for (int k = j; k < pageCount-1; k ++) { 
   
// memoryList[k] = memoryList[k+1];
// }
// memoryList[pageCount-1] = temp;
//
// //修改访问情况
// isVisited = 1;
// //修改访问时间
// //展示
// printf("%d\n",strList[i]);
// break;
// }
//
// if (memoryList[j] == -1) { 
   
// //页面不在内存中且内存未满->直接存入
// memoryList[j] = strList[i];
// //修改访问情况
// isVisited = 1;
//
// pageCount ++;
//
// //展示
// printf("%d\n",strList[i]);
// showMemoryList(memoryList, phyNum);
// break;
// }
// }
//
// if (!isVisited) { 
   
// //需要换页
// //1.直接将数组整体往前移一位
// for (int k = 0; k < phyNum; k ++) { 
   
// memoryList[k] = memoryList[k+1];
// }
// //2.将当前页面加到队尾
// memoryList[phyNum-1] = strList[i];
// //展示
// printf("%d\n",strList[i]);
// showMemoryList(memoryList, phyNum);
// }
//
//
// }
//}
int main(int argc, const char * argv[]) { 
   
    
    //物理块的数量
    int phyBlockNum;
    printf("请输入物理块数量:\n");
    scanf("%d",&phyBlockNum);
    
    //生成内存队列
    int memoryList[phyBlockNum];
    //初始化内存状态
    initializeList(memoryList, phyBlockNum);
    //showMemoryList(memoryList,phyBlockNum);
    
    //页面数量
    int pageNum;
    printf("请输入要访问的页面总数:\n");
    scanf("%d",&pageNum);
    
    //保存页面号引用串
    int pageNumStrList[pageNum];
    printf("请输入要访问的页面号:\n");
    for (int i = 0; i < pageNum; i ++) { 
   
        scanf("%d",&pageNumStrList[i]);
    }
    showList(pageNumStrList, pageNum);
    
    int chose;
    while (1) { 
   
        printf("请选择所需的置换算法:\n");
        printf("1.OPT 2.FIFO 3.LRU 4.退出\n");
        scanf("%d",&chose);
        
        switch (chose) { 
   
            case 1:
                showList(pageNumStrList, pageNum);
                replacePageByOPT(memoryList, phyBlockNum, pageNumStrList, pageNum);
                //重新初始化内存
                initializeList(memoryList, phyBlockNum);
                break;
            case 2:
                showList(pageNumStrList, pageNum);
                replacePageByFIFO(memoryList, phyBlockNum, pageNumStrList, pageNum);
                //重新初始化内存
                initializeList(memoryList , phyBlockNum);
                break;
            case 3:
                showList(pageNumStrList, pageNum);
                replacePageByLRU(memoryList, phyBlockNum, pageNumStrList, pageNum);
                //重新初始化内存
                initializeList(memoryList, phyBlockNum);
                break;
            default:
                return 0;
                break;
        }
    }
    
    return 0;
}

实验截图

img_7
img_8
img_9

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/125616.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • NDT Matching 算法学习

    NDT Matching 算法学习问题背景近来从事毫米波雷达的定位与建图工作,想拓展下工作思路,研究autoware公司的激光点云定位与建图。期间正好发现autoware的激光点云配准算法是NDT(Normal-DistributionsTransform),相比ICP算法,它能更快速高效地确定两个大型点云的刚性变换。这里分别介绍下2003年经典的2DNDT算法,以及autoware日本团队在2006年提出的3DND…

    2022年10月23日
  • mapGetters 辅助函数「建议收藏」

    mapGetters 辅助函数「建议收藏」1:mapGetters:辅助函数mapGetters:辅助函数mapGetters:辅助函数仅仅将store中的getter映射到局部计算属性:1:import{mapGetters}from’vuex’2:exportdefault{computer:{//使用对象展开运算符将getter混入computer对象中…mapGetters([‘getMachin…

  • 国际标准时间哪个时区_北京时间与世界时间的换算

    国际标准时间哪个时区_北京时间与世界时间的换算关于时间格式2016-08-9T10:01:54.123Z20160809100154.123Z处理方法今天遇到了一个奇怪的时间格式如以下格式,下面两种时间格式所表示的时间是同一个时间,这个不难理解//UTC时间,世界标准时间2016-08-9T10:01:54.123Z20160809100154.123Z如图所示,这是一张由网友提供的图片,里面显示的是时间UTC…

    2022年10月22日
  • ioctl() FIONREAD 检测socket是否有数据可读

    ioctl() FIONREAD 检测socket是否有数据可读先看看FIONREAD的作用FIONREAD:Getthenumberofbytesintheinputbuffer获取接收缓存中数据的字节数项目中用来判断tcpsocket是否有数据接收到,但是出现了一个问题,对于用于accept的socket即调用listen()之后的socket,用FIONREAD,判断的时候报错,ioctl()返回-1,错误码是2…

  • c语言中putchar的用法举例_putchar和getchar

    c语言中putchar的用法举例_putchar和getcharC语言中getchar()和putchar()的用法getchar()和putchar()是一对字符输入/输出函数.getchar()不带任何参数,他从输入序列中返回下一个字符。例如,下面的语句读取下一个字符输入,并把该字符的值赋给变量ch:ch=getcha();putchar()函数打印它的参数。例如,下面的语句把之前赋给ch的值作为字符打印出来:putchar(ch);由于这两个函数只处理字符,所以他们通常比scanf()和printf()函数更快更便捷。而且,ge

    2022年10月18日
  • Django(64)频率认证源码分析与自定义频率认证「建议收藏」

    Django(64)频率认证源码分析与自定义频率认证「建议收藏」前言有时候我们发送手机验证码,会发现1分钟只能发送1次,这是做了频率限制,限制的时间次数,都由开发者自己决定频率认证源码分析defcheck_throttles(self,request):

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号