操作系统之存储管理——FIFO算法和LRU算法

简介: 存储管理的主要功能之一是合理地分配空间。请求页式管理是一种常用的虚拟存储管理技术。本实验的目的是通过请求页式管理中页面置换算法模拟设计,了解虚拟存储技术的特点,掌握请求页式存储管理的页面置换算法。

要求



一、实验目的


存储管理的主要功能之一是合理地分配空间。请求页式管理是一种常用的虚拟存储管理技术。

本实验的目的是通过请求页式管理中页面置换算法模拟设计,了解虚拟存储技术的特点,掌握请求页式存储管理的页面置换算法。


二、实验内容


(1)通过计算不同算法的命中率比较算法的优劣。同时也考虑了用户内存容量对命中率的影响。


页面失效次数为每次访问相应指令时,该指令所对应的页不在内存中的次数。

在本实验中,假定页面大小为1k,用户虚存容量为32k,用户内存容量为4页到32页。


(2)produce_addstream通过随机数产生一个指令序列,共320条指令。


A、指令的地址按下述原则生成:


1)50%的指令是顺序执行的

2)25%的指令是均匀分布在前地址部分

3)25%的指令是均匀分布在后地址部分


B、具体的实施方法是:


1)在[0,319]的指令地址之间随机选取一起点m;

2)顺序执行一条指令,即执行地址为m 1的指令;

3)在前地址[0,m 1]中随机选取一条指令并执行,该指令的地址为m’;

4)顺序执行一条指令,地址为m’ 1的指令

5)在后地址[m’ 2,319]中随机选取一条指令并执行;

6)重复上述步骤1)~5),直到执行320次指令


C、将指令序列变换称为页地址流


在用户虚存中,按每k存放10条指令排列虚存地址,即320条指令在虚存中的存放方式为:

第0条~第9条指令为第0页(对应虚存地址为[0,9]);

第10条~第19条指令为第1页(对应虚存地址为[10,19]);

。。。。。。

第310条~第319条指令为第31页(对应虚存地址为[310,319]);


按以上方式,用户指令可组成32页。

(3)计算并输出下属算法在不同内存容量下的命中率。

1)先进先出的算法(FIFO);

2)最近最少使用算法(LRU);

3)最佳淘汰算法(OPT);

4)最少访问页面算法(LFR);

其中3)和4)为选择内容


三、系统框图



20181204155745451.png


一、运行结果


a、运行程序:终端先显示:

Start memory management.

Producing address flow, wait for while, please.


b、地址流、地址页号流生成后,终端显示:


There are algorithms in the program

1、Optimization algorithm

2、Least recently used algorithm

3、First in first out algorithm

4、Least frequently used algorithm

Select an algorithm number, please.


用户输入适当淘汰算法的号码,并按回车,若是第一次选择,输出相应的地址页号流。然后输出该算法分别计算的用户内存从2k ~ 32k时的命中率,若输入的号码不再1~4中,则显示:


there is not the algorithm in the program,并重复b。


c、输出结果后,终端显示 “do you try again with anther algorithm(y/n)”。若键入y则重复b,否则

结束。(一般讲四种算法都用过后结束,以便比较)。


二、运行结果讨论


1、比较各种算法的命中率

2、分析当用户内存容量增加是对命中率的影响


分析



上面就是实验要求,因为时间关系,只写了fifo和lru两种,但是这两个会了,剩下的了解算法原理就很容易实现。


对于两种算法的理解和实现为:


先进先出算法算法(Fifo):


这个算法原理没有算法,就是先进先出。对于这个结构最好采用的就算队列了,对于java而言,我用的是list集合,每次添加数据的时候添加到第0位置,而如果移除的时候移除末尾的页数。在这个过程中,每执行一条指令的时候,如果这个指令对应的地址(指令/10)在list中,那么就命中,否则就是缺页,需要移除尾,在0位置添加元素。


举个例子,页面内存为3,(只能存三页),要执行指令地址页面对应为:4 2 3 4 1 2 1 5 6 3


那么流程顺序为:(4)缺页—>(2,4)缺页—>(3,2,4)缺页—>4命中—>(1,3,2)缺页4被置换—>2命中—>1命中—>(5,1,3)缺页2被替换—>(6,5,1)缺页2被替换—>(3,6,5)缺页1被替换。


最近最少使用算法(LRU):


这个算法跟fifo其实还是挺像的,但是有一点区别,最近最少使用。也就是说在一个正常序列的时候如果命中的化,就会把这个地址的页号移动到首位(或者链表首位)。而如果缺页的时候,要把这个链表的末尾位置移除,因为末尾的元素是最近用的最少的(很久前才有的)。对于数据结构,我依然选择Arraylist。每次遇到指令地址的时候我只需要特殊判断下就可以了。我只为了实验的目的,没有考虑性能,因为检查是否存在地址的时候我用了list.contains()方法,这是线性查询复杂度O(n),如果数据量大可以list map组合使用,将查询降低到O(logn).还可以开一个boolean数组标记让查询复杂度降低到O(1),(但是这样的化增大空间),还好数据量不大,影响不大。


如果页面内存为3,(只能存三页),要执行指令地址页面对应为:4 2 3 4 1 2 1 5 6 3

那么流程顺序为(4)—>(2,4)—>(3,2,4)—>(4,3,2)命中—>(1,4,3)缺页2被替换—>(2,1,4)缺页—>(1,2,4)命中—>(5,1,2)缺页—>(6,5,1)缺页—>(3,6,5)缺页


代码



大致流程就是这样,有一点区别。

下面附上我的ac代码。有的解释会在注释中:


package 实验;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.List;
import java.util.Queue;
import java.util.Scanner;
public class storemanage {
  static int mingzhong;
  static int lenyeliu=320;
  static int errortime;//失效次数
  static int random[]=new int[330];//随机指令
  static Scanner sc=new  Scanner(System.in);
  static void init()//初始随机数
  {
    int index=0;
    while(index<320)
    {
      int m=(int) (Math.random()*320);
      random[index++]=m;//顺序指令
      int m1=(int) (Math.random()*(m+1));
      if(m1==320) {continue;}//跳出问本次
      random[index++]=m1;//前地址部分 最大317
      if(m1+1==320) {continue;}//跳出问本次
      random[index++]=m1+1;//顺序指令
      int m2=(int) (Math.random()*(319-(m1+2))+m1+2);
      if(m2==320) {continue;}//跳出问本次
      random[index++]=m2;//后地址
      if(index>320)
      {
        break;
      }     
    }
  }
  private static void  lur()
  {
    for(int memory=2;memory<=32;memory++)
    {
      mingzhong=0;errortime=0;
        Queue<Integer>q1=new ArrayDeque<>();
        int index=0;
        while(index<320)
        {
          if(q1.size()<memory)
          {
            if(q1.contains(random[index]/10))
            {
             q1.remove(random[index]/10);
             mingzhong++;
             q1.add(random[index]/10);
            }
            else
            {
              q1.add(random[index]/10);
              errortime++;
            }
          }
          else
          {
            if(q1.contains(random[index]/10))
              {
               q1.remove(index);
               mingzhong++;
              }
              else
              {
                q1.poll();//抛出
                q1.add(random[index]/10);
                errortime++;
              }
          }
          index++;
        }
        double minz=1-(double)(errortime/(double)(320));//mingzhong/320一样
        String minzhon=String.format("%.4f", minz);
        System.out.println("lur :memory:"+memory+" 缺失个数:"+errortime+" 命中个数"+mingzhong+"  命中率:"+minzhon);
    }
    System.out.println("书否继续Y/N");
    String team=sc.next();
    if(team.equals("Y"))
    {
      System.out.println("请输入编号");
      int index=sc.nextInt();
      if(index==1) {fifo();}
      else
      {
        lur();
      }
    }
  }
  private static void fifo() {
    // TODO 自动生成的方法存根
    for(int memory=2;memory<=32;memory++)
    {
      mingzhong=0;errortime=0;
        List<Integer>list=new ArrayList<>();
        int index=0;
        while(index<320)
        {
          if(list.size()<memory)//小于内存
          {
           if(list.contains(random[index]/10)) {mingzhong++;}
           else
           {
             list.add(random[index]/10);
             errortime++;
           }           
          }
          else//内存慢了
          {
               if(list.contains(random[index]/10)) {mingzhong++;}
             else
             {
               list.remove(0);//移除第一个
               list.add(random[index]/10);
               errortime++;
             }
          }
          index++;
         // System.out.println(index);
         }
        double minz=1-(double)(errortime/(double)(320));//mingzhong/320一样
        String minzhon=String.format("%.4f", minz);
        System.out.println("fifo :memory:"+memory+" 缺失个数:"+errortime+" 命中个数"+mingzhong+"  命中率:"+minzhon);
    }
    System.out.println("书否继续Y/N");
    String team=sc.next();
    if(team.equals("Y"))
    {
      System.out.println("请输入编号");
      int index=sc.nextInt();
      if(index==1) {fifo();}
      else
      {
        lur();
      }
    }
  }
  public static void main(String[] args) {
    init();
    System.out.println("随机数为");
    for(int i=0;i<320;i++)
    {
      System.out.print(String.format("%5d", random[i]));
      if((i+1)%20==0)System.out.println();
    }
    System.out.println("输入选择算法的计算方式序号\n1:先进先出的算法(FIFO);\n" + 
        "2:最近最少使用算法(LRU);\n" + 
        "3:最佳淘汰算法(OPT);\n" + 
        "4:最少访问页面算法(LFR);");
    int index=sc.nextInt();
    if(index==1) {
      fifo();
    }
    else if(index==2)
    {
      lur();
    }   
  }
}


执行结果




20190721130945495.png


fifo


20190721131005456.png


lur


20190721131056581.png


可以看得出成功了。并且最后都是0.9因为固定缺页数(首次命中)达到0.1.


目录
相关文章
|
9天前
|
算法 调度 UED
深入理解操作系统之进程调度算法
【9月更文挑战第9天】在操作系统的心脏跳动中,进程调度扮演着关键角色,就如同指挥家控制交响乐的节奏。本文将通过浅显易懂的语言和生动的比喻,带领读者走进进程调度的世界,探索不同调度算法背后的哲学与实践,以及它们如何影响系统的性能和用户体验。从最简单的先来先服务到复杂的多级队列和反馈循环,我们将一同见证操作系统如何在众多任务中做出选择,确保系统的高效与公平。
|
25天前
|
缓存 算法 前端开发
深入理解缓存淘汰策略:LRU和LFU算法的解析与应用
【8月更文挑战第25天】在计算机科学领域,高效管理资源对于提升系统性能至关重要。内存缓存作为一种加速数据读取的有效方法,其管理策略直接影响整体性能。本文重点介绍两种常用的缓存淘汰算法:LRU(最近最少使用)和LFU(最不经常使用)。LRU算法依据数据最近是否被访问来进行淘汰决策;而LFU算法则根据数据的访问频率做出判断。这两种算法各有特点,适用于不同的应用场景。通过深入分析这两种算法的原理、实现方式及适用场景,本文旨在帮助开发者更好地理解缓存管理机制,从而在实际应用中作出更合理的选择,有效提升系统性能和用户体验。
53 1
|
19天前
|
存储 算法 调度
深入理解操作系统:进程调度的算法与实现
【8月更文挑战第31天】在操作系统的核心,进程调度扮演着关键角色,它决定了哪个进程将获得CPU的使用权。本文不仅剖析了进程调度的重要性和基本概念,还通过实际代码示例,展示了如何实现一个简单的调度算法。我们将从理论到实践,一步步构建起对进程调度的理解,让读者能够把握操作系统中这一复杂而精妙的部分。
|
19天前
|
算法 调度 开发者
深入理解操作系统:进程管理与调度算法
在数字时代的心脏,操作系统扮演着至关重要的角色。它不仅是计算机硬件与软件之间的桥梁,更是确保多任务高效运行的守护者。本文将带你一探操作系统中进程管理的奥秘,并通过实际代码示例深入解析进程调度算法。无论你是编程新手还是资深开发者,了解这些基础概念都将有助于你更好地理解计算机工作原理,并提升你对系统性能调优的认识。准备好,让我们一起揭开操作系统的神秘面纱!【8月更文挑战第31天】
|
19天前
|
算法 调度
探索操作系统的心脏:进程调度算法揭秘
【8月更文挑战第31天】本文将带领读者深入理解操作系统中至关重要的一环——进程调度。通过浅显易懂的语言和逐步深入的内容安排,我们将从基础概念入手,探讨进程调度的目的和挑战,进而分析几种常见的调度算法。文中不仅提供了丰富的代码示例,还设计了互动问题,鼓励读者思考并应用所学知识。让我们一起揭开操作系统进程调度的神秘面纱,看看它是如何在幕后支撑着我们日常使用的电脑和移动设备的顺畅运行。
|
1月前
|
算法 程序员
理解操作系统内存管理:页面置换算法全解析
大家好,我是小米,热爱分享技术的大哥哥!今天聊的是操作系统中的页面置换算法。它解决的是内存满载时,如何选择合适的页面移出以腾出空间的问题。主要有三种算法:FIFO(先进先出),简单但性能不佳;LRU(最近最久未使用),考虑时间局部性,性能较好但实现较复杂;OPT(最佳置换),理论上最优但无法实际应用。这些算法各有千秋,在实际应用中需根据场景选择最合适的方案。希望这能帮大家更好地理解内存管理的核心机制!
72 2
|
2月前
|
算法 大数据 调度
探索操作系统的心脏:进程调度算法
【7月更文挑战第31天】在数字世界的复杂编织中,操作系统扮演着枢纽的角色,而进程调度则是其跳动的心脏。本文将深入探讨几种常见的进程调度算法,通过代码示例揭示它们对系统性能的影响,并讨论如何根据应用场景选择恰当的调度策略。
22 1
|
1月前
|
存储 缓存 算法
深入解析B树:数据结构、存储结构与算法优势
深入解析B树:数据结构、存储结构与算法优势
|
1月前
|
存储 算法
【数据结构与算法】队列(顺序存储)
【数据结构与算法】队列(顺序存储)
12 0
|
2月前
|
算法 调度 UED
深入理解操作系统之进程调度算法
【7月更文挑战第31天】在操作系统的设计中,进程调度是核心功能之一,它直接关系到系统性能和用户体验。本文将探讨几种常见的进程调度算法,并通过代码示例加深理解。我们将从理论到实践,一探究竟。
25 0