操作系统实验(5)—— 页面淘汰算法模拟实现与比较

本文详细介绍了操作系统中五种常见的页面置换算法——最佳淘汰算法(OPT)、先进先出淘汰算法(FIFO)、最近最久未使用淘汰算法(LRU)、简单Clock淘汰算法(NRU)及其改进版。通过C语言实现,模拟了随机页面访问序列,并对比了它们的缺页率和性能。实验结果显示,最优算法的缺页率最低,而FIFO算法的缺页率最高。此外,还探讨了不同算法的实现思想和优缺点。

页面淘汰算法模拟实现与比较

1. 实验目的

理解并掌握主要页面淘汰算法的设计和实现要旨。

2. 实验内容

利用标准 C 语言,编程设计与实现最佳淘汰算法、先进先出淘汰算法、最近最久未使用淘汰算法、简单 Clock 淘汰算法及改进型 Clock 淘汰算法,并随机发生页面访问序列开展有关算法的测试及性能比较。

3. 实验要求

本实验课题功能设计要求如下:

  1. 编程设计实现最佳淘汰算法OPT、先进先出淘汰算法FIFO、最近最久未使用淘汰算法LRU、简单Clock 淘汰算法及改进型 Clock 淘汰算法
  2. 编程设计实现页面访问序列的随机发生机制,包括各页面读写访问方式的设定以满足改进型 Clock 淘汰算法的要求;
  3. 在执行进程和访问各页面过程中,每访问一个(或一次)页面应显示输出当时的进程页表内容(包括页号、物理块号、状态位、读/写访问方式等字段)及本次页面访问操作情况(譬如页面已在内存或触发缺页中断);
  4. 基于相同的条件,包括系统均采用固定分配局部置换策略相同的进程逻辑地址空间大小(暨逻辑页面数,设进程逻辑地址空间的页面总数为 N,则其页号取值区间为[0, N))、分配给进程同样多的物理块(设进程分配获得 S 个物理块,则相应物理块号分别标记为 PF0、PF1、……、PFS-1)、相同的页面访问序列(整数序列,整数取值区间为[0, N))、均预装入前三个页面,进行有关算法的测试;
  5. 变换上述条件实施多次测试,统计分析和比较有关算法的性能(譬如缺页率、淘汰页查找时间开销)。

关于页面访问序列随机发生机制的设计思想:

  • 初始化进程逻辑地址空间页面总数 N、各逻辑页面的读写访问方式(是否支持写访问,即 R、RW)、工作集起始页号 s(s∈[0, N))、工作集中包含的页数 w,工作集移动速率 v(每处理 v 个页面访问,就将工作集起始页号递增即 s+1)以及一个取值区间为[0, 1]的值 t;
  • 生成取值区间为[s, min(s+w, N-1)]的 v 个随机数并添加保存到页面访问序列中,同 时为每次页面访问分别生成一个取值区间为[0, 1]的随机数,若该随机数值大于 0.7 且对应所访问页面支持写访问则设定以写方式访问相应页面,否则以读方式访问对应页面;
  • 生成取值区间为[0, 1]的一个随机数 r,并比较 r 与 t 的大小;
  • 若 r < t,则为 s 生成一个新值(s∈[0, N)),否则 s = (s + 1) mod N;
  • 如果想继续加大页面访问序列的长度,返回第 2 步,否则结束。

4. 实验过程

4.0 整体设计

4.0.1 数据结构

  • 页表结构设计

假设虚拟内存的地址是16位,页面大小为1K,则进程的大小为 2 16 = 64 K B 2^{16}=64KB 216=64KB

分页个数 = 进程的大小 页面的大小 = 逻辑地址表示的大小 页面的大小 = 2 16 B 1 K B = 2 6 页 分页个数=\frac{进程的大小}{页面的大小}=\frac{逻辑地址表示的大小}{页面的大小}=\frac{2^{16B}}{1KB}=2^{6}页 分页个数=页面的大小进程的大小=页面的大小逻辑地址表示的大小=1KB216B=26

因此页号P占用前6位,页内偏移量W=16-6=10位。每一个页表项占用2B,因此页表存储空间需要 2 6 ∗ 2 B = 128 B 2^6*2B=128B 262B=128B

页面结构以及页表项设计如下:

struct PageInfo       //页面信息结构
 {
   
   
    int  pages[MAX];  // 模拟的最大访问页面数
    int  isVisited;         // 标志位,0表示无页面访问数据
    int  page_missing_num;    // 缺页中断次数
    int  allocated_page_num;     // 分配的页框数
    int  visit_list_length;     // 访问页面序列长度
} pInfo;

struct MemInfo  // 页表项信息
{
   
   
    int time; //记录页框中数据的访问次数
    int isVisit;//访问位
    int isModify;//修改位
    int pages;//页号
}mInfo;
  • 关键全局变量
MemInfo pageList[MAX];         // 分配的页框
int  page_loss_num = 0;        // 缺页次数
int  current_page;             //页面访问指针
int  replace_page;             //页面替换指针
int  is_loss_page;             //缺页标志:1->缺页,0->命中

4.0.2 主要函数

  • Init 初始化
void Init()
{
   
   
    int i, pn;
    is_loss_page = 0;              //缺页标志,0为不缺页,1为缺页
    pInfo.page_missing_num = 0;   // 缺页次数
    pInfo.isVisited = 0;        // 标志位,0表示无页面访问数据
    printf("请输入分配的页框数:");   // 自定义分配的页框数
    scanf("%d", &pn);
    pInfo.allocated_page_num = pn;
    for (i = 0; i < MAX; i++)   // 清空页面序列
    {
   
   
            pInfo.pages[i] = -1;
    }
}
  • getRandomList 随机生成访问序列

算法流程如下:

  1. 确定虚拟内存的尺寸N,工作集的起始位置p,工作集中包含的页数e,工作集移动率m(每处理m个页面访问则将起始位置p +1),
  2. 以及一个范围在0和1之间的值t;
  3. 生成m个取值范围在p和p + e间的随机数,并记录到页面访问序列串中;
  4. 生成一个随机数r,0 ≤ r ≤ 1;如果r < t,则为p生成一个新值,否则p = (p + 1) mod N;
  5. 如果想继续加大页面访问序列串的长度,请返回第2步,否则结束。

具体实现如下:

void getRandomList(int m, int e, int s)
{
   
   
    int pl;
    Init();     //初始化
    printf("请输入访问序列的长度:");
    scanf("%d", &pl); //随机生成访问序列的长度
    pInfo.visit_list_length = pl;
    srand((unsigned)time(NULL)); // 随机种子
    int  p = rand() % MAX; //在0——MAX范围内随机初始化工作集的起始位置p
    int i, j=0;
    double t= rand() % 10 / 10.0; // 一个范围在0和1之间的值t
    for (i = 0; i < s; i++) // 重复s次
    {
   
   
        if (j > pInfo.visit_list_length) // 不能超过访问序列的长度
            break;
        for (j = i * m; j < (i + 1) * m; j++)//生成m个取值范围在p~p + e间的随机数
        {
   
   
            pInfo.pages[j]= (p + (rand() % e)) % MAX; //并记录到页面访问序列串中;
        }
        double r = (rand() % 10) / 10.0;// 生成一个范围在0-1之间的随机数r
        if (r < t) // 如果r < t,则为p生成一个新值
            p = rand() % MAX;
        else
        {
   
   
            p = (p + 1) % MAX; //否则向后循环移位
        }
    }
}
  • showState跟踪显示状态信息

算法流程如下:

  1. 如果current_page=0, 则说明当前页面指针处于起始位置,则首先遍历pInfo.pages[i]数组,打印页面的访问序列。其具体格式为每行显示10个等访问的页面。
  2. 打印当前要访问的页号
  3. 打印当前页框内已经有的页面号
  4. 通过is_loss_page 判断是否发生中断。如果发生中断,则用缺页数/已访问的页面数计算得到缺页率并显示给用户。

具体实现如下:

void showState(void)
{
   
   
    int i, n;
    if (current_page == 0)
    {
   
   
        printf("\n~~~~~~~~~~~~~~~~~页面访问序列~~~~~~~~~~~~~~~~~\n");
        for (i = 0; i < pInfo.visit_list_length; i++)
        {
   
   
            printf("%4d", pInfo.pages[i]);
            if ((i + 1) % 10 == 0) printf("\n");   //每行显示10个
        }
        printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
    }
    printf("访问%3d -->内存空间[", pInfo.pages[current_page]); // 访问当前页面信息
    for (n = 0; n < pInfo.allocated_page_num; n++)     // 页框信息
        {
   
   
        if (pageList[n].pages >= 0)
            printf("%3d", pageList[n].pages);
        else
            printf("   ");
        }
    printf(" ]");
    if (is_loss_page == 1)     //缺页标志,0为不缺页,1为缺页
        {
   
   
        printf(" --> 缺页中断 --> ");
        if (current_page == 0)
        {
   
   
            printf("缺页率 = %3.1f", (float)(pInfo.page_missing_num) * 100.00 );
        }
        else{
   
   
            printf("缺页率 = %3.1f", (float)(pInfo.page_missing_num) * 100.00 / current_page); }
        }
    printf("\n");
}

  • isExist 查找页面是否已经在内存中

算法流程如下:

  1. 遍历所有在内存中的页面,同时使得访问次数加1
  2. 然后再次遍历内存,寻找匹配页号的页表项
  3. 如果找到该页表项,则置is_loss_page缺页标志=0(不缺页),同时访问次数time 也置为0,然后通过随机生成的0或者1,来设置该访问页面是否被修改。并返回1。
  4. 如果没有找到该页面,则缺页中断的次数+1,同时返回0。
int isExist(int page)
{
   
   
    int n;
    for (n = 0; n < pInfo.allocated_page_num; n++)
        pageList[n].time++;   // 访问次数加1
    for (n = 0; n < pInfo.allocated_page_num; n++)
    {
   
   
        if (pageList[n].pages == page)
        {
   
   
            is_loss_page = 0;    //is_loss_page缺页标志=0(不缺页)
            pageList[n].time = 0;   //置访问次数为0
            pageList[n].isVisit = 1; // 访问标志
            if (randBool()) {
   
          
                pageList[n].isModify = 1; // 修改标志
            }
            return 1;
        }
    }
    is_loss_page = 1;  	//页面不存在,缺页
    return 0;
}

其中调用了randBool()函数,随机的生成0或者1,其具体实现如下

bool randBool()
{
   
   
    if ((rand() % 2 + 1) == 1)
        return true;
    else
        return false;
}

4.1 最佳淘汰算法(OPT)

4.1.1 原理介绍

算法规则:选择永不使用或是在最长时间内不再被访问(即距现在最长时间才会被访问)的页面淘汰出内存。

假定系统为某进程分配了三个物理块,并考虑有以下页面访问序列:
[7, 0, 1, 2, 0, 3, 0, 4, 2, 3, 0, 3, 2, 1, 2, 0, 1, 7, 0, 1]
进程运行时,先将7, 0, 1三个页面依次装入内存。进程要访问页面2时,产生缺页中断,根据最佳置换算法,选择第18次访问才需调入的页面7予以淘汰。然后,访问页面0时,因为已在内存中所以不必产生缺页中断。访问页面3时又会根据最佳置换算法将页面1淘汰……依此类推。

页面 7 0 1 2 0 3 0 4 2 3 0 3 2 1 2 0 1 7 0 1
页面1 7 7 7 2 2 2 2 2 7
页面2 0 0 0 0 4 0 0 0
页面3 1 1 3 3 3 1 1
缺页

4.1.2 代码实现

算法流程图如下:

在这里插入图片描述

OPT 算法具体实现如下:

void OPT()
{
   
   
    
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zyw2002

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值