页面置换算法(FIFO&LRU)

页面置换算法

实验目的

1.通过模拟实现几种基本页面置换的算法,了解虚拟存储技术的特点。
2.通过置换算法的模拟和比较,进一步了解它们的优缺点。
3.锻炼知识的运用能力和实践能力

实验要求

编写程序实现:先进先出页面置换算法(FIFO)和最近最久未使用页面置换算法(LRU)
说明:(1)关于页面走向的页地址流可利用随机数产生一个序列,模拟该页地址流,
也可以手工键盘输入的方式或读取文件中的页地址流。(2)初始时,假定所有页面均
不在内存。(3)计算并输出以上两种算法在分配不同内存物理块数时(讨论内存物理
块数分配为3,4,5)的缺页率。(4)至少验证两组数据,即页地址流。

实验内容概述

首先,了解页面算法的功能。页面的算法的功能是当出现缺页异常且调入新页面而内存已满时,置换算法选择被置换的物理页面进行置换。因此对于如何科学地选取被置换的物理页面根据不同的页面置换算法不同而不同。

其次,页面置换算法的设计目标是为了减少页面的调入调出次数,把未来不再访问或者短期内不访问的页面调出。常见的页面置换调度算法有先进先出页面置换算法(FIFO)、最近最久未使用页面置换算法(LRU)、最佳置换调度算法(OPT)、CLOCK置换算法等。

本次实验针对FIFO和LRU两种算法进行详细分析和模拟实验,深刻理解页面调度算法原理。

算法流程图

总体流程:
总体流程图FIFO流程:
FIFO流程LRU流程图:
LRU流程图

程序代码

#include <stdio.h>
#define phy 100
#define page 100//页面最大数
#define phyBlock 100//物理块最大数
//物理块的数量
int phyBlockNum;
//页面数量
int pageNum;
//保存页面号引用串
int pageNumStrList[page];
//初始化队列
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("***********结果展示***********\n");
    printf("缺页次数:%d\n", missingCount);
    printf("缺页率:%d/%d\n", missingCount, pageNum);
    double result = (double)(pageNum - missingCount) / (double)pageNum;
    printf("置换次数:%d\n", replaceCount);
    printf("******************************\n");
}

//找到该页面下次要访问的位置
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 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[phy];
    //初始化
    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] != -1) {
                timeRecord[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);
}

int main(int argc, const char* argv[])
{
    printf("***********************************\n");
    printf("*            页面调度算法         *\n");
    printf("***********************************\n");

    printf("请输入物理块数量:\n");
    scanf("%d", &phyBlockNum);
    //生成内存队列
    int memoryList[phyBlock];
    //初始化内存状态
    initializeList(memoryList, phyBlockNum);
    //showMemoryList(memoryList,phyBlockNum);
    printf("请输入要访问的页面总数:\n");
    scanf("%d", &pageNum);
    printf("请输入要访问的页面号:\n");
    for (int i = 0; i < pageNum; i++) {
        scanf("%d", &pageNumStrList[i]);
    }
    printf("*******************************\n");
    showList(pageNumStrList, pageNum);
    printf("*******************************\n");
    int chose;
    while (1)
    {
        printf("请选择所需的置换算法(1.FIFO 2.LRU 3.退出):\n");
        scanf("%d", &chose);
        printf("*******************************\n");
        switch (chose)
        {
        case 1:
            showList(pageNumStrList, pageNum);
            printf("*******************************\n");
            replacePageByFIFO(memoryList, phyBlockNum, pageNumStrList, pageNum);
            //重新初始化内存
            initializeList(memoryList, phyBlockNum);
            break;
        case 2:
            showList(pageNumStrList, pageNum);
            printf("*******************************\n");
            replacePageByLRU(memoryList, phyBlockNum, pageNumStrList, pageNum);
            //重新初始化内存
            initializeList(memoryList, phyBlockNum);
            break;
        default:
            return 0;
            break;
        }
    }
    return 0;
}

实验结果截图

  • 测试数据1:物理内存块分别为{3,4,5},页面长度为20,页面地址流为{7,0,1,2,0,3,0,4,2,3,0,3,2,1,2,0,1,7,0,1}

数据输入截图:物理内存块为3
数据输入
FIFO结果:
FIFO
LRU结果:
LRU后面结果读者就自己去实验啦。

实验分析

本次实验通过对两种页面置换算法即先进先出置换算法(FIFO)以及最近最久未使用算法(LRU)进行了实验模拟,为了保证程序能够正常运行,系统必须从内存中调出一页内存放在磁盘上,以便将所需要的页调入内存,该过程称为页面调度,通过对以上两种算法的模拟,从中我深刻理解了两种算法的深层原理。本次实验要求基本达到,实验结果达到预期效果,下面是本次实验的收获以及心得:

物理内存块数量的增大可能使缺页率不降反增,这与该算法不考虑程序的动态特征有关;

影响缺页率的因素不是单一的,主存页框数,页面大小,页面替换算法、程序特征均会影响缺页率;

每种算法各有各的优缺点,例如FIFO算法简单,但通常缺页率较高,而LRU通常缺页率较FIFO低,但算法比较复杂,选择时各有取舍。

### FIFO 和 LRU 页面置换算法的工作原理 #### FIFO (First-In, First-Out) FIFO 是一种简单的页面置换算法,其基本思想是按照页面进入内存的时间顺序进行替换。最早进入内存的页面最先被移除。 当发生缺页中断时,操作系统会选择最先进入内存的那个页面将其淘汰并加载新的页面。这种方法实现简单,只需要维护一个队列即可记录页面进入内存的先后次序[^1]。 ```python class FIFOPageReplacement: def __init__(self): self.queue = [] def page_fault(self, new_page): if new_page not in self.queue: if len(self.queue) >= max_pages: # 当达到最大容量时 removed_page = self.queue.pop(0) # 移除最早的页面 self.queue.append(new_page) ``` #### LRU (Least Recently Used) LRU 算法基于程序访问局部性的假设,即最近最少使用的页面在未来一段时间内也不太可能会被再次访问。因此,在发生缺页异常时,优先选择那些距离当前时刻最长未被访问过的页面作为被淘汰的对象。 为了有效地跟踪各个页面最后被访问的时间戳,通常会采用链表结构或其他数据结构来保存这些信息,并随着每次页面访问更新相应的状态。 ```python from collections import OrderedDict class LRUPageReplacement: def __init__(self): self.cache = OrderedDict() def get(self, key): if key in self.cache: value = self.cache.pop(key) self.cache[key] = value # 更新位置到最新 return True return False def put(self, key): if key not in self.cache and len(self.cache) >= max_pages: oldest_key = next(iter(self.cache)) del self.cache[oldest_key] self.cache[key] = None ``` 两种算法的主要区别在于: - **效率**:FIFO 实现起来非常容易,但是性能上不如 LRU;而 LRU 虽然更复杂一些,但在很多情况下能够提供更好的命中率。 - **公平性**:由于 FIFO 不考虑实际使用情况只看进入时间,可能导致某些经常使用的页面也被错误地替换了;相比之下,LRU 更加合理地反映了真实的应用场景需求。 - **适应能力**:对于具有较强空间局部性特征的工作负载来说,LRU 表现出明显的优势,因为它可以更好地保留近期活跃的数据集。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值