选择调出页面的算法就称为页面置换算法。好的页面置换算法应有较低的页面更换频率,也就是说,应将以后不会再访问或者以后较长时间内不会再访问的页面先调出。

常见的置换算法有以下四种(以下来自操作系统课本)。

1. 最佳置换算法(OPT)

最佳(Optimal, OPT)置换算法所选择的被淘汰页面将是以后永不使用的,或者是在最长时间内不再被访问的页面,这样可以保证获得最低的缺页率。但由于人们目前无法预知进程在内存下的若千页面中哪个是未来最长时间内不再被访问的,因而该算法无法实现。

最佳置换算法可以用来评价其他算法。假定系统为某进程分配了三个物理块,并考虑有以下页面号引用串:
    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淘汰……依此类推,如图3-26所示。从图中可以看出釆用最佳置换算法时的情况。

可以看到,发生缺页中断的次数为9,页面置换的次数为6。

访问页面 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    
缺页否                        
    图3-26  利用最佳置换算法时的置换图

2. 先进先出(FIFO)页面置换算法

优先淘汰最早进入内存的页面,亦即在内存中驻留时间最久的页面。该算法实现简单,只需把调入内存的页面根据先后次序链接成队列,设置一个指针总指向最早的页面。但该算法与进程实际运行时的规律不适应,因为在进程中,有的页面经常被访问。

访问页面 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 4 4 4 0     0 0     7 7 7
物理块2   0 0 0   3 3 3 2 2 2     1 1     1 0 0
物理块3     1 1   1 0 0 0 3 3     3 2     2 2 1
缺页否          
    图3-27  利用FIFO置换算法时的置换图
这里仍用上面的实例,釆用FIFO算法进行页面置换。进程访问页面2时,把最早进入内存的页面7换出。然后访问页面3时,再把2, 0, 1中最先进入内存的页换出。由图 3-27可以看出,利用FIFO算法时进行了 12次页面置换,比最佳置换算法正好多一倍。

FIFO算法还会产生当所分配的物理块数增大而页故障数不减反增的异常现象,这是由 Belady于1969年发现,故称为Belady异常,如图3-28所示。只有FIFO算法可能出现Belady 异常,而LRU和OPT算法永远不会出现Belady异常。

访问页面 1 2 3 4 1 2 5 1 2 3 4 5
物理块1 1 1 1 4 4 4 5     5 5  
物理块2   2 2 2 1 1 1     3 3  
物理块3     3 3 3 2 2     2 4  
缺页否      
    1 1 1     5 5 5 5 4 4
物理块2*   2 2 2     2 1 1 1 1 5
物理块3*     3 3     3 3 2 2 2 2
物理块4*       4     4 4 4 3 3 3
缺页否      
    图 3-28   Belady 异常

3. 最近最久未使用(LRU)置换算法

选择最近最长时间未访问过的页面予以淘汰,它认为过去一段时间内未访问过的页面,在最近的将来可能也不会被访问。该算法为每个页面设置一个访问字段,来记录页面自上次被访问以来所经历的时间,淘汰页面时选择现有页面中值最大的予以淘汰。

再对上面的实例釆用LRU算法进行页面置换,如图3-29所示。进程第一次对页面2访问时,将最近最久未被访问的页面7置换出去。然后访问页面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   4 4 4 0     1   1   1    
物理块2   0 0 0   0   0 0 3 3     3   0   0    
物理块3     1 1   3   3 2 2 2     2   2   7    
缺页否                
   图3-29  LRU页面置换算法时的置换图

在图3-29中,前5次置换的情况与最佳置换算法相同,但两种算法并无必然联系。实际上,LRU算法根据各页以前的情况,是“向前看”的,而最佳置换算法则根据各页以后的使用情况,是“向后看”的。

LRU性能较好,但需要寄存器和栈的硬件支持。LRU是堆栈类的算法。理论上可以证明,堆栈类算法不可能出现Belady异常。FIFO算法基于队列实现,不是堆栈类算法。

4. 时钟(CLOCK)置换算法

LRU算法的性能接近于OPT,但是实现起来比较困难,且开销大;FIFO算法实现简单,但性能差。所以操作系统的设计者尝试了很多算法,试图用比较小的开销接近LRU的性能,这类算法都是CLOCK算法的变体。

简单的CLOCK算法是给每一帧关联一个附加位,称为使用位。当某一页首次装入主存时,该帧的使用位设置为1;当该页随后再被访问到时,它的使用位也被置为1。对于页替换算法,用于替换的候选帧集合看做一个循环缓冲区,并且有一个指针与之相关联。当某一页被替换时,该指针被设置成指向缓冲区中的下一帧。当需要替换一页时,操作系统扫描缓冲区,以查找使用位被置为0的一帧。每当遇到一个使用位为1的帧时,操作系统就将该位重新置为0;如果在这个过程开始时,缓冲区中所有帧的使用位均为0,则选择遇到的第一个帧替换;如果所有帧的使用位均为1,则指针在缓冲区中完整地循环一周,把所有使用位都置为0,并且停留在最初的位置上,替换该帧中的页。由于该算法循环地检查各页面的情况,故称为CLOCK算法,又称为最近未用(Not Recently Used, NRU)算法。

CLOCK算法的性能比较接近LRU,而通过增加使用的位数目,可以使得CLOCK算法更加高效。在使用位的基础上再增加一个修改位,则得到改进型的CLOCK置换算法。这样,每一帧都处于以下四种情况之一:

  1. 最近未被访问,也未被修改(u=0, m=0)。
  2. 最近被访问,但未被修改(u=1, m=0)。
  3. 最近未被访问,但被修改(u=0, m=1)。
  4. 最近被访问,被修改(u=1, m=1)。

算法执行如下操作步骤:

  1. 从指针的当前位置开始,扫描帧缓冲区。在这次扫描过程中,对使用位不做任何修改。选择遇到的第一个帧(u=0, m=0)用于替换。
  2. 如果第1)步失败,则重新扫描,查找(u=0, m=1)的帧。选择遇到的第一个这样的帧用于替换。在这个扫描过程中,对每个跳过的帧,把它的使用位设置成0。
  3. 如果第2)步失败,指针将回到它的最初位置,并且集合中所有帧的使用位均为0。重复第1步,并且如果有必要,重复第2步。这样将可以找到供替换的帧。

改进型的CLOCK算法优于简单CLOCK算法之处在于替换时首选没有变化的页。由于修改过的页在被替换之前必须写回,因而这样做会节省时间。

#include <iostream>
#include<map>
#include<set>
#include <algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#define N 200
using namespace std; int page[N];//页面引用号
int block[N];//物理块,内存
int dist[N][N];//表示第i次访问内存的时候,内存中的页面j 在以后被访问的最小时间 int n;//页面引用号个数
int m;//物理块数目
int page_max;//最大页面号 int pre[N];//page[i]在page中的索引
int opt(){//最佳页面置换算法
int page_lack = ;
memset(pre, , sizeof(pre));
memset(dist, 0x3f, sizeof(dist));
memset(block, -, sizeof(block));
for(int i=n; i>=; --i){
for(int j=; j<=page_max; ++j)
if(pre[j])
dist[i][j] = pre[j] - i;
pre[page[i]] = i;
} for(int i=; i<=n; ++i){//开始访问页面,初始是内存中没有分页
int j;
int max_dist = , p;
for(j=; j<=m; ++j){
if(block[j] == -){//改块没有放入页面,则直接放入, 产生缺页
block[j] = page[i];
cout<<"页面"<<page[i]<<"不在内存,直接放入物理块"<<j<<"中!"<<endl;
page_lack++;
break;
} else if(block[j] == page[i])//页面存在内存中
break; if(max_dist < dist[i][block[j]]){
max_dist = dist[i][block[j]];//说明block[j] 对应的页面以后会长时间不会用到
p = j;//block[] 第j个页面会被替换掉
}
}
if(j > m){//此时内存中不能在放入新的分页,而且没有找到page[i]对应的分页,接下来进行页面替换
cout<<"页面"<<page[i]<<"不在内存,将物理块"<<p<<"中的页面" <<block[p]<<"替换掉!"<<endl;
block[p] = page[i];
page_lack++;
}
cout<<endl<<"当前内存中页面的情况:"<<endl;
for(int k=; k<=m; ++k)//内存中页面加载情况
cout<<block[k]<<" ";
cout<<endl<<endl;
}
return page_lack;//返回缺页次数
} int lru(){//最近最久未使用算法和opt算法差不多,只不过是lru是向前看, opt是向后看
int page_lack = ;
memset(pre, , sizeof(pre));
memset(dist, 0x3f, sizeof(dist));
memset(block, -, sizeof(block));
for(int i=; i<=n; ++i){
for(int j=; j<=page_max; ++j)
if(pre[j])
dist[i][j] = i - pre[j];
pre[page[i]] = i;
} for(int i=; i<=n; ++i){//开始访问页面,初始是内存中没有分页
int j;
int max_dist = , p;
for(j=; j<=m; ++j){
if(block[j] == -){//改块没有放入页面,则直接放入, 产生缺页
block[j] = page[i];
cout<<"页面"<<page[i]<<"不在内存,直接放入物理块"<<j<<"中!"<<endl;
page_lack++;
break;
} else if(block[j] == page[i])//页面存在内存中
break; if(max_dist < dist[i][block[j]]){
max_dist = dist[i][block[j]];//说明block[j] 对应的页面以后会长时间不会用到
p = j;//block[] 第j个页面会被替换掉
}
}
if(j > m){//此时内存中不能在放入新的分页,而且没有找到page[i]对应的分页,接下来进行页面替换
cout<<"页面"<<page[i]<<"不在内存,将物理块"<<p<<"中的页面" <<block[p]<<"替换掉!"<<endl;
block[p] = page[i];
page_lack++;
}
cout<<endl<<"当前内存中页面的情况:"<<endl;
for(int k=; k<=m; ++k)//内存中页面加载情况
cout<<block[k]<<" ";
cout<<endl<<endl;
}
return page_lack;//返回缺页次数
} set<int>page_set;
int fifo(){//先进先出页面置换算法
int page_lack = ;
memset(block, -, sizeof(block));
int index = ;
for(int i=; i<=n; ++i){
if(index > m) index = ;
set<int>::iterator it;
it = page_set.find(page[i]);
if(it == page_set.end()){
if(block[index] != -)
page_set.erase(block[index]);
page_set.insert(page[i]);
block[index++] = page[i];
++page_lack;
}
for(int k=; k<=m; ++k)
cout<<block[k]<<" ";
cout<<endl;
}
return page_lack;
} int nru[N];//表示 物理块 i 最近时候被访问过
int page_in_block[N];//页面 i 在 block的下标索引
int clock(){
int index = ;
int page_lack = ;
memset(block, -, sizeof(block));
for(int i=; i<=n; ++i){
if(page_in_block[page[i]]){//如果page[i]已经在内存中
nru[page_in_block[page[i]]] = ;//重新标记这个物理块中的页面被访问过了
cout<<endl<<"第"<<i<<"次: 页面"<<page[i]<<"已经存在物理块"<< page_in_block[page[i]] << "中!"<<endl;
}
else {
while(true){
if(index > m) index = ;
if(block[index] == -) {
nru[index] = ;
page_in_block[page[i]] = index;
block[index++] = page[i];
++page_lack;
break;
}
if(block[index] == page[i]){
nru[index++] = ;
break;
} else {
if(nru[index] == ){//替换该页面
nru[index] = ;
page_in_block[block[index]] = ;
cout<<endl<<"第"<<i<<"次: 物理块"<<index<<"中的页面"<< block[index] <<"最近未被使用,将要被页面"<<page[i]<<"替换!"<<endl;
page_in_block[page[i]] = index;
block[index++] = page[i];
++page_lack;
break;
} else
nru[index++] = ;
}
}
}
for(int k=; k<=m; ++k)
cout<<block[k]<<" ";
cout<<endl;
}
return page_lack;
} int main(){
cin>>n>>m;
for(int i=; i<=n; ++i){
cin>>page[i];
page_max = max(page_max, page[i]) ;
}
cout<<"opt缺页中断次数:"<<opt()<<endl;
cout<<"***********************************"<<endl;
cout<<"lru缺页中断次数:"<<lru()<<endl;
cout<<"***********************************"<<endl;
cout<<"fifo缺页中断次数:"<<fifo()<<endl;
cout<<"***********************************"<<endl;
cout<<"clock缺页中断次数:"<<clock()<<endl;
return ;
}
/*
20 3
7 0 1 2 0 3 0 4 2 3 0 3 2 1 2 0 1 7 0 1 12 3
2 3 2 1 5 2 4 5 3 2 5 2
*/

操作系统页面置换算法(opt,lru,fifo,clock)实现的更多相关文章

  1. 操作系统 页面置换算法LRU和FIFO

    LRU(Least Recently Used)最少使用页面置换算法,顾名思义,就是替换掉最少使用的页面. FIFO(first in first out,先进先出)页面置换算法,这是的最早出现的置换 ...

  2. 操作系统页面置换算法之FIFO,LRU

    #include<iostream> #include<unistd.h> #include<vector> #include<wait.h> #inc ...

  3. 页面置换算法(最佳置换算法、FIFO置换算法、LRU置换算法、LFU置换算法)

    页面置换产生的原因是:分页请求式存储管理(它是实现虚拟存储管理的方法之一,其中一个特性是多次性-->多次将页面换入或换出内存) 效果最好的页面置换算法:最佳置换算法 比较常用的页面置换算法有:F ...

  4. 操作系统笔记(六)页面置换算法 FIFO法 LRU最近最久未使用法 CLOCK法 二次机会法

    前篇在此: 操作系统笔记(五) 虚拟内存,覆盖和交换技术 操作系统 笔记(三)计算机体系结构,地址空间.连续内存分配(四)非连续内存分配:分段,分页 内容不多,就不做index了. 功能:当缺页中断发 ...

  5. (待续)C#语言中的动态数组(ArrayList)模拟常用页面置换算法(FIFO、LRU、Optimal)

    目录 00 简介 01 算法概述 02 公用方法与变量解释 03 先进先出置换算法(FIFO) 04 最近最久未使用(LRU)算法 05 最佳置换算法(OPT) 00 简介 页面置换算法主要是记录内存 ...

  6. 页面置换算法 - FIFO、LFU、LRU

    缓存算法(页面置换算法)-FIFO. LFU. LRU 在前一篇文章中通过leetcode的一道题目了解了LRU算法的具体设计思路,下面继续来探讨一下另外两种常见的Cache算法:FIFO. LFU ...

  7. 操作系统-2-存储管理之LRU页面置换算法(LeetCode146)

    LRU缓存机制 题目:运用你所掌握的数据结构,设计和实现一个  LRU (最近最少使用) 缓存机制. 它应该支持以下操作: 获取数据 get 和 写入数据 put . 获取数据 get(key) - ...

  8. 【操作系统】页面置换算法(最佳置换算法)(C语言实现)

    [操作系统]页面置换算法(最佳置换算法)(C语言实现) (编码水平较菜,写博客也只是为了个人知识的总结和督促自己学习,如果有错误,希望可以指出) 1.页面置换算法: 在地址映射过程中,若在页面中发现所 ...

  9. 虚存管理页面置换算法 — FIFO和RUL算法模拟实现

    本篇博文为追忆以前写过的算法系列第一篇(20081021) 温故知新 目的: 为了解决内存容量有限与多作业执行的冲突.运用了虚拟存储技术.能从逻辑上对内存进行扩充,达到扩充内存的效果.分页存储管理是实 ...

随机推荐

  1. [翻译svg教程]svg中的circle元素

    svg中的<circle> 元素,是用来绘制圆形的,例如 <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink= ...

  2. 接口测试SoapUI参数化

    上次和大家一起完成了soapui的参数之一properties,今天我们一起交流另外一种参数化的方法,跟着一起练习,不懂不要紧,练习多了就会慢慢懂的: 1.准备excle(目前soapui只支持xls ...

  3. WPF-系统托盘

    WPFSystemTray.cs public class WPFSystemTray { /// <summary> /// 设置系统托盘 /// </summary> // ...

  4. VMware创建Linux虚拟机并安装CentOS(三)

    选择“创建自定义布局”手动给Linux指定系统分区.交换分区,鼠标单击“下一步”按钮继续. 首先创建交Swap分区,鼠标单击“创建”按钮,在弹出的“生成存储”对话框中,生成分区选择“标准分区”:鼠标单 ...

  5. 【Silverlight】打开Silverlight程序报错,"未找到导入的项目......请确认<Import>声明中的路径正确,且磁盘上存在该文件"

    在打开Silverlight程序时,报错(如图所示),程序使用的是Visual Studio 2013和最新的Silverlight版本(Silverlight5). 然后我在网上找了下说:Silve ...

  6. Codeforces Round #361 (Div. 2) B

    B - Mike and Shortcuts Description Recently, Mike was very busy with studying for exams and contests ...

  7. Python2 基本数据结构源码解析

    Python2 基本数据结构源码解析 Contents 0x00. Preface 0x01. PyObject 0x01. PyIntObject 0x02. PyFloatObject 0x04. ...

  8. thinkphp 缓存数据

    thinkphp 中内置了缓存操作 3.1版本的数据缓存方法是cache 基本用法: S(array('type'=>'xcache','expire'=>60)); 缓存初始化 缓存初始 ...

  9. php 中的 基本区别点

    this.self.parent https://my.oschina.net/jackguo/blog/189020

  10. Daily Scrum02 12.15

    今天会议主要还是大家汇报进度与任务.由于团队中有两位成员在周一会有其他事情处理,暂不分配任务,因而这些事情要交给其他成员处理…… 由于要反复修改,查看效果,所以要花费很长的时间,但大家最近都很忙,我们 ...