操作系统系列
学习至此,发现很多学了但很久没用的知识,久而久之,慢慢遗忘。等哪天还需要的话,却发现已经忘得差不多了,即使整理了文档(word等),还是得从头再学一遍。读研第一学期,发现很多东西都可以从博客上学习到,也有不少博主呕心沥血整理了挺多有用的博文。于是,本人借此契机,也慢慢开始整理一些博文,不断改进完善中。整理博文(IT)有如下目的:
- 首要目的:记录“求学生涯”的所学所悟,不断修改,不断更新!(有读者的互动)
- 其次目的:在这“开源”的时代,整理并分享所学所悟是一种互利的行为!
6个实验相关代码的下载地址:http://download.csdn.net/detail/houchaoqun_xmu/9865648
-------------------------------
虚拟内存页面置换算法
一、概念介绍和案例解析 - 页面置换算法
- 最佳(Optimal)置换算法:
但由于人们目前还无法预知一个进程在内存的若干个页面中,哪一个页面是未来最长时间内不再被访问的,因而该算法是无法实现的,但可以利用该算法去评价其它算法。现举例说明如下。
假定系统为某进程分配了三个物理块,并考虑有以下的页面号引用串:
7,0,1,2,0,3,0,4,2,3,0,3,2,1,2,0,1,7,0,1
进程运行时,先将7,0,1三个页面装入内存。以后,当进程要访问页面2时,将会产生缺页中断。此时OS根据最佳置换算法,将选择页面7予以淘汰。这是因为页面0将作为第5个被访问的页面,页面1是第14个被访问的页面,而页面7则要在第18次页面访问时才需调入。下次访问页面0时,因它已在内存而不必产生缺页中断。当进程访问页面3时,又将引起页面1被淘汰;因为,它在现有的1,2,0三个页面中,将是以后最晚才被访问的。图4-26示出了采用最佳置换算法时的置换图。由图可看出,采用最佳置换算法发生了6次页面置换。
- 先进先出(FIFO)页面置换算法:
该算法实现简单,只需把一个进程已调入内存的页面,按先后次序链接成一个队列,并设置一个指针,称为替换指针,使它总是指向最老的页面。
但该算法与进程实际运行的规律不相适应,因为在进程中,有些页面经常被访问,比如,含有全局变量、常用函数、例程等的页面,FIFO算法并不能保证这些页面不被淘汰。
Belady现象的描述:一个进程P要访问M个页,OS分配N个内存页面给进程P;对一个访问序列S,发生缺页次数为PE(S,N)。当N增大时,PE(S, N)时而增大,时而减小。
Belady现象的原因:FIFO算法的置换特征与进程访问内存的动态特征是矛盾的,即被置换的页面并不是进程不会访问的。
- 最近最久未使用(LRU)置换算法:
当进程第一次对页面3进行访问时,第1页成为最近最久未使用的页,将它换出。
由图可以看出,前5个时间的图像与最佳置换算法时的相同,但这并非是必然的结果。
因为,最佳置换算法是从“向后看”的观点出发的,即它是依据以后各页的使用情况;
而LRU算法则是“向前看”的,即根据各页以前的使用情况来判断,而页面过去和未来的走向之间并无必然的联系。
为了了解一个进程在内存中的各个页面各有多少时间未被进程访问,以及如何快速地知道哪一页是最近最久未使用的页面,须有两类硬件之一的支持:寄存器或栈。
【寄存器】为了记录某进程在内存中各页的使用情况,须为每个在内存中的页面配置一个移位寄存器,可表示为
R = Rn-1Rn-2Rn-3 … R2R1R0
当进程访问某物理块时,要将相应寄存器的Rn-1位置成1。此时,定时信号将每隔一定时间(例如100 ms)将寄存器右移一位。如果我们把n位寄存器的数看做是一个整数,那么,具有最小数值的寄存器所对应的页面,就是最近最久未使用的页面。
下图示出了某进程在内存中具有8个页面,为每个内存页面配置一个8位寄存器时的LRU访问情况。这里,把8个内存页面的序号分别定为1~8。由图可以看出,第3个内存页面的R值最小,当发生缺页时,首先将它置换出去。
4,7,0,7,1,0,1,2,1,2,6
随着进程的访问,栈中页面号的变化情况如下图所示。在访问页面6时发生了缺页,此时页面4是最近最久未被访问的页,应将它置换出去。
Linux 的LRU算法
最初分配某个页时, 页的寿命为3, 每次页被访问, 其寿命增加3, 直到20为止。当内核的交换进程运行时(kswapd周期运行), 在内存的所有页面寿命减1。如果某个页的寿命为0,则该页作为交换候选页。二、实验介绍
- 问题描述:
设计程序模拟先进先出FIFO、最佳置换OPI和最近最久未使用LRU页面置换算法的工作过程。假设内存中分配给每个进程的最小物理块数为m,在进程运行过程中要访问的页面个数为n,页面访问序列为P1, … ,Pn,分别利用不同的页面置换算法调度进程的页面访问序列,给出页面访问序列的置换过程,计算每种算法缺页次数和缺页率。
- 程序要求:
1)利用先进先出FIFO、最佳置换OPI和最近最久未使用LRU三种页面置换算法模拟页面访问过程。
2)模拟三种算法的页面置换过程,给出每个页面访问时的内存分配情况。
3)输入:最小物理块数m,页面个数n,页面访问序列P1, …,Pn,算法选择1-FIFO,2-OPI,3-LRU。
4)输出:每种算法的缺页次数和缺页率。
三、程序设计和程序开发
const int MaxNumber=100;
int PageOrder[MaxNumber]; //页面序列
int PageNum,LackNum,MinBlockNum; //页面个数,缺页次数,最小物理块数
int PageDisCount[MaxNumber]; //当前内存距离下一次出现的距离
int LRUtime[MaxNumber]; //存储队列中各个页面最近使用情况
double LackPageRate; //缺页率
int LackPageNum; //缺页数
int VirtualQueue[MaxNumber]; //虚拟队列
页面置换的实现过程如下:
- 1.变量初始化;
- 2.接收用户输入最小物理块数m,页面个数n,页面序列P1, … ,Pn,选择算法1-FIFO,2-OPI,3-LRU;
- 3.根据用户选择的算法进行页面的分配和置换,输出页面置换算法的模拟过程;
- 4.计算选择算法的缺页次数和缺页率;
- 5.输出选择算法的缺页次数和缺页率。
FIFO过程:
void FIFO()
{
cout<<"********* 你选择了FIFO算法:********* "<<endl;
cout<<"页面置换情况如下:"<<endl;
initial();
bool isInQueue;
int point = 0; //指向最老的页面
for (int i = MinBlockNum;i<PageNum;i++)
{
isInQueue = false;
for (int k = 0;k<MinBlockNum;k++)
{
if (VirtualQueue[k] == PageOrder[i]) //如果当前页面在队列中
{
isInQueue = true;
}
}
if (!isInQueue) //如果当前页面不在队列中,则进行相应的处理
{
LackPageNum++; //缺页数加1
VirtualQueue[point] = PageOrder[i];
display();
point++;
if (point == MinBlockNum)
{
point = 0; //当point指向队尾后一位的时候,将point重新指向队首
}
}
}
LackPageRate = (LackPageNum * 1.0)/PageNum;
cout<<"缺页数LackPageNum = "<<LackPageNum<<endl;
cout<<"缺页率LackPageRate = "<<LackPageRate<<endl;
}
OPI过程:
void OPI()
{
cout<<"********* 你选择了OPI算法:********* "<<endl;
cout<<"页面置换情况如下:"<<endl;
initial();
bool isInQueue;
int dis; //表示队列每个值距离下一次访问的距离
int point; //指向最长时间未被访问的下标
for(int i = MinBlockNum;i<PageNum;i++)
{
isInQueue = false;
for (int k = 0;k<MinBlockNum;k++)
{
if (VirtualQueue[k] == PageOrder[i]) //如果当前页面在队列中
{
isInQueue = true;
}
}
if (!isInQueue)
{
LackPageNum++;
//计算当前队列每一页对应的下一次出现的距离
for (int s = 0;s < MinBlockNum;s++)
{
dis = 1;
for (int t = i;t<PageNum;t++) //从页面序列的第i个位置开始找起
{
if (VirtualQueue[s] != PageOrder[t])
{
dis++;
}
else
{
break;
}
}
PageDisCount[s] = dis;
}
point = 0;
for (int m = 1;m < MinBlockNum;m++)
{
if (PageDisCount[point] < PageDisCount[m])
{
point = m;
}
}
VirtualQueue[point] = PageOrder[i];
display();
}//if
}//for
LackPageRate = (LackPageNum*1.0)/PageNum;
cout<<"缺页数LackPageNum = "<<LackPageNum<<endl;
cout<<"缺页率LackPageRate = "<<LackPageRate<<endl;
}
LRU过程:
void LRU()
{
cout<<"********* 你选择了LRU算法:********* "<<endl;
cout<<"页面置换情况如下:"<<endl;
initial();
bool isInQueue;
int point,k; //指向最长时间未被访问的下标
for(int i = MinBlockNum;i<PageNum;i++)
{
isInQueue = false;
for (k = 0;k<MinBlockNum;k++)
{
if (VirtualQueue[k] == PageOrder[i]) //如果当前页面在队列中
{
isInQueue = true;
}
}
if (!isInQueue)
{
LackPageNum++;
point = 0;
for (int j = 1;j<MinBlockNum;j++)
{
if (LRUtime[point]<LRUtime[j])
{
point = j;
}
}
for (int s = 0;s<MinBlockNum;s++)//其余页面对应的时间要+1
{
if (VirtualQueue[s] != VirtualQueue[point])
{
LRUtime[s]++;
}
}
VirtualQueue[point] = PageOrder[i];
LRUtime[point] = 0;
display();
}//if
else //负责更新当前对应页面的时间
{
for (int s = 0;s<MinBlockNum;s++)//其余页面对应的时间要+1
{
if (VirtualQueue[s] != PageOrder[i])
{
LRUtime[s]++;
}
else
LRUtime[s] = 0;
}
}
}//for
LackPageRate = (LackPageNum*1.0)/PageNum;
cout<<"缺页数LackPageNum = "<<LackPageNum<<endl;
cout<<"缺页率LackPageRate = "<<LackPageRate<<endl;
}
四、实验结果分析
- 实验数据:
3
20
7 0 1 2 0 3 0 4 2 3 0 3 2 1 2 0 1 7 0 1
- 实验结果:
五、实验源码
// 操作系统_实验五(虚拟内存页面置换算法).cpp : 定义控制台应用程序的入口点。
//
#include <iostream>
#include <fstream>
#include <iomanip>
using namespace std;
const int MaxNumber=100;
int PageOrder[MaxNumber]; //页面序列
int PageNum,LackNum,MinBlockNum; //页面个数,缺页次数,最小物理块数
int PageDisCount[MaxNumber]; //当前内存距离下一次出现的距离
int LRUtime[MaxNumber]; //存储队列中各个页面最近使用情况
double LackPageRate; //缺页率
int LackPageNum; //缺页数
int VirtualQueue[MaxNumber]; //虚拟队列
void input();
void initial();
void FIFO(); //先进先出
void OPI(); //最佳置换
void LRU(); //最近最久未使用LRU页面置换算法
void display();
void input()
{
ifstream readData;
readData.open("data.txt");
readData>>MinBlockNum;
readData>>PageNum;
for (int i=0;i<PageNum;i++)
{
readData>>PageOrder[i];
}
cout<<"读取数据结果如下:"<<endl;
cout<<"最小物理块数 = "<<MinBlockNum<<endl;
cout<<"页面个数 = "<<PageNum<<endl;
cout<<"页面序列如下:"<<endl;
for (int i = 0;i<PageNum;i++)
{
cout<<PageOrder[i]<<" ";
}
cout<<endl;
}
void initial()
{
LackPageNum = MinBlockNum;
LackPageRate = 0.0;
for(int i = 0;i<PageNum;i++)
{
PageDisCount[i] = 0; //初始化距离都为0
VirtualQueue[i] = -1; //初始化队列的值都为负数
}
for (int i = 0;i<MinBlockNum;i++)
{
bool isInQueue2 = false;
int dis = 0;
LRUtime[i] = 0;
for (int j = 0;j<MinBlockNum;j++)
{
if (VirtualQueue[j] == PageOrder[i])
{
isInQueue2 = true;
}
}
if (!isInQueue2) //当有新的进程进入到队列时,便计算其对应的距离
{
VirtualQueue[i] = PageOrder[i];
for (int k = 0;k<i;k++)
{
LRUtime[k]++; //之前的页面对应的时间+1
}
display();
}
else
{
LRUtime[i] = 0; //重新更新为0,表示最近刚刚使用
}
}
}
void FIFO()
{
cout<<"********* 你选择了FIFO算法:********* "<<endl;
cout<<"页面置换情况如下:"<<endl;
initial();
bool isInQueue;
int point = 0; //指向最老的页面
for (int i = MinBlockNum;i<PageNum;i++)
{
isInQueue = false;
for (int k = 0;k<MinBlockNum;k++)
{
if (VirtualQueue[k] == PageOrder[i]) //如果当前页面在队列中
{
isInQueue = true;
}
}
if (!isInQueue) //如果当前页面不在队列中,则进行相应的处理
{
LackPageNum++; //缺页数加1
VirtualQueue[point] = PageOrder[i];
display();
point++;
if (point == MinBlockNum)
{
point = 0; //当point指向队尾后一位的时候,将point重新指向队首
}
}
}
LackPageRate = (LackPageNum * 1.0)/PageNum;
cout<<"缺页数LackPageNum = "<<LackPageNum<<endl;
cout<<"缺页率LackPageRate = "<<LackPageRate<<endl;
}
void OPI()
{
cout<<"********* 你选择了OPI算法:********* "<<endl;
cout<<"页面置换情况如下:"<<endl;
initial();
bool isInQueue;
int dis; //表示队列每个值距离下一次访问的距离
int point; //指向最长时间未被访问的下标
for(int i = MinBlockNum;i<PageNum;i++)
{
isInQueue = false;
for (int k = 0;k<MinBlockNum;k++)
{
if (VirtualQueue[k] == PageOrder[i]) //如果当前页面在队列中
{
isInQueue = true;
}
}
if (!isInQueue)
{
LackPageNum++;
//计算当前队列每一页对应的下一次出现的距离
for (int s = 0;s < MinBlockNum;s++)
{
dis = 1;
for (int t = i;t<PageNum;t++) //从页面序列的第i个位置开始找起
{
if (VirtualQueue[s] != PageOrder[t])
{
dis++;
}
else
{
break;
}
}
PageDisCount[s] = dis;
}
point = 0;
for (int m = 1;m < MinBlockNum;m++)
{
if (PageDisCount[point] < PageDisCount[m])
{
point = m;
}
}
VirtualQueue[point] = PageOrder[i];
display();
}//if
}//for
LackPageRate = (LackPageNum*1.0)/PageNum;
cout<<"缺页数LackPageNum = "<<LackPageNum<<endl;
cout<<"缺页率LackPageRate = "<<LackPageRate<<endl;
}
void LRU()
{
cout<<"********* 你选择了LRU算法:********* "<<endl;
cout<<"页面置换情况如下:"<<endl;
initial();
bool isInQueue;
int point,k; //指向最长时间未被访问的下标
for(int i = MinBlockNum;i<PageNum;i++)
{
isInQueue = false;
for (k = 0;k<MinBlockNum;k++)
{
if (VirtualQueue[k] == PageOrder[i]) //如果当前页面在队列中
{
isInQueue = true;
}
}
if (!isInQueue)
{
LackPageNum++;
point = 0;
for (int j = 1;j<MinBlockNum;j++)
{
if (LRUtime[point]<LRUtime[j])
{
point = j;
}
}
for (int s = 0;s<MinBlockNum;s++)//其余页面对应的时间要+1
{
if (VirtualQueue[s] != VirtualQueue[point])
{
LRUtime[s]++;
}
}
VirtualQueue[point] = PageOrder[i];
LRUtime[point] = 0;
display();
}//if
else //负责更新当前对应页面的时间
{
for (int s = 0;s<MinBlockNum;s++)//其余页面对应的时间要+1
{
if (VirtualQueue[s] != PageOrder[i])
{
LRUtime[s]++;
}
else
LRUtime[s] = 0;
}
}
}//for
LackPageRate = (LackPageNum*1.0)/PageNum;
cout<<"缺页数LackPageNum = "<<LackPageNum<<endl;
cout<<"缺页率LackPageRate = "<<LackPageRate<<endl;
}
void display()
{
for (int i = 0;i<MinBlockNum && VirtualQueue[i]>=0;i++)
{
cout<<VirtualQueue[i]<<" ";
}
cout<<endl;
}
int main()
{
input();
int isContinue = 1;
int chooseAlgorithm;
while(isContinue)
{
cout<<"******************************************************"<<endl;
cout<<"********* 请选择算法 **********"<<endl;
cout<<"********* 1代表FIFO算法 **********"<<endl;
cout<<"********* 2代表OPI算法 **********"<<endl;
cout<<"********* 3代表LRU算法 **********"<<endl;
cin>>chooseAlgorithm;
switch(chooseAlgorithm)
{
case 1:
FIFO();
break;
case 2:
OPI();
break;
case 3:
LRU();
break;
default:
cout<<"请输入正确的序号进行选择:"<<endl;break;
}
cout<<"********** 是否继续选择算法? **********"<<endl;
cout<<"********** 输入1代表继续,输入0代表退出! **********"<<endl;
cin>>isContinue;
}
cout<<"***************************结束***************************"<<endl;
system("pause");
return 0;
}