16281035
我的github网址,里面有源码,查看详情请点击
为什么会有页面置换算法?
图5. 虚拟内存和物理内存以及磁盘的映射关系
由图5可以看出,虚拟内存实际上可以比物理内存大。当访问虚拟内存时,会访问MMU(内存管理单元)去匹配对应的物理地址(比如图5的0,1,2),而如果虚拟内存的页并不存在于物理内存中(如图5的3,4),会产生缺页中断,从磁盘中取得缺的页放入内存,如果内存已满,还会根据某种算法将磁盘中的页换出。
MMU中存储页表,用来匹配虚拟内存和物理内存。页表中每个项通常为32位,即4byte,除了存储虚拟地址和页框地址之外,还会存储一些标志位,比如是否缺页,是否修改过,写保护等。因为页表中每个条目是4字节,现在的32位操作系统虚拟地址空间是232,假设每页分为4k,也需(232/(4*2^10))*4=4M的空间,为每个进程建立一个4M的页表并不明智。因此在页表的概念上进行推广,产生二级页表,虽然页表条目没有减少,但内存中可以仅仅存放需要使用的二级页表和一级页表,大大减少了内存的使用。
每个进程有4GB的虚拟地址空间,每个进程自己的一套页表。程序中使用的都是4GB地址空间中的虚拟地址。而访问物理内存,需要使用物理地址。
要求:模拟的虚拟内存的地址为16位,页面大小为1K,模拟的物理内存有32K。
经过计算可得该计算机的页面最大64个,物理块最大值为32个。所以在程序设计时,页面及物理块大小均不可以超过最大值,否则将在程序界面中进行提示,用户重新输入。
为了验证方便,我将这个页面访问序列随机生成的代码作为另一个新主程序,这样验证起来比较直观。
后边的源代码我会把这段程序作为一个页面访问序列随机生成函数放入主程序中。
代码的详细解释都在注释中:
#include
#include
#include
#include
const int DataMax = 64;
const int BlockNum = 32;
int Data[DataMax]; // 保存数据
int Block[BlockNum]; // 物理块
int count[BlockNum]; // 计数器
int N ; // 页面个数
int M;//最小物理块数
#define Q 999
using namespace std;
int main()
{
int p = 1;//设置工作集的起始位置为1
int e = 4;//工作集包含的页数为4
int m = 5;//处理5个页面后工作集开始移动
float t = 0.637;//判断p是否跳转的依据
float r; //随机生成,与t比较
int j = 0;//保存随机生成的页面的数组下标
cout<<"请输入最小物理块数:";
cin>>M;
while(M > BlockNum) // 大于数据个数
{
cout<<"物理块数超过预定值,请重新输入:";
cin>>M;
}
cout<<"请输入页面的个数:";
cin>>N;
while(N > DataMax) // 大于数据个数
{
cout<<"页面个数超过预定值,请重新输入:";
cin>>N;
}
srand((int)time(NULL));//用time(0)的返回值当种子
for(int o=0;o<(N/m-1);o++)
{
for(int i=0;i
可以看到4次随机生成的r值都比t=0.637要大,所以p会一直在初始设定的p到p+e之间,也就是闭区间【1,5】之间。可见我们的生成序列是正确的。
这次设定页面为30个。
(1) 最初始直接生成5个【p,p+e】之间的页面,也就是【1,5】闭区间上。
(2) 0.537<0.637,p的新值为23,生成页面在【23,27】闭区间上。
(3) 0.64>0.637,生成页面在【4,7】闭区间上。
(4) 0.458<0.637,p的新值为28,生成页面在【28,32】闭区间上。
(5) 0.229<0.637,p的新值为7,生成页面在【7,11】闭区间上。
(6) 0.917>0.637,生成页面在【3,7】闭区间上。
for(int o=0;o<(N/m);o++)
{
for(int i=0;i
外层循环的计数应当在0到(N/m-1)之间,因为第一次的五个数是随机生成的,不需要比较r和t的大小。比如页面最大为30个,则需要生成5个随机数r,而不是六个。
if(r
我认为p = (p+1) % M这样处理其实不太有利于页面的局部性原理
从上面测试2就可以看出这样生成其实页面的缺页率会很大。
我认为的改进办法是p = (p+1),不用mod M,这样就能保证在原来页面的基础上增加,符合页面局部性原理。
void DataCreate()
{
cout<<"请输入最小物理块数:";
cin>>M;
while(M > BlockNum) // 大于数据个数
{
cout<<"物理块数超过预定值,请重新输入:";
cin>>M;
}
cout<<"请输入页面的个数:";
cin>>N;
while(N > DataMax) // 大于数据个数
{
cout<<"页面个数超过预定值,请重新输入:";
cin>>N;
}
int p = 1;
int e = 4;
int m = 5;//处理4个页面后起始位置P+1
float t = 0.637;
float r;
int j = 0;
srand((int)time(NULL));//用time(0)的返回值当种子
for(int o=0;o<(N/m);o++)
{
for(int i=0;i
int main(int argc, char* argv[])
{
DataCreate();// DataInput();
// FIFO();
// Optimal();
// LRU();
// return 0;
int menu;
while(true)
{
cout<>menu;
switch(menu)
{
case 1: FIFO();break;
case 2: Optimal();break;
case 3: LRU();break;
default: break;
}
if(menu!=1&&menu!=2&&menu!=3) break;
}
}
int main(){
char ch ;
DataCreate();
for(int i = 0; i < PageCount; i++){
cout<>ch;
switch(ch){
case '1':{
lost = 0;
count = 0;
for(int m = 0; m < A; m++){
state[m] = 0;
}
for(int j = 0; j < A; j++){
Inside[j] = 0;
}
for(int i = 0; i < PageCount; i++){
cout<<"读入Page["<
void Optimal()
{
int i,j,k;
bool find;
int point;
int temp; // 临时变量,比较离的最远的时候用
ChangeTimes = 0;
for(j=0;j M ) // 因为i是从0开始记,而BlockNum指的是个数,从1开始,所以i+1
{
//获得要替换的块指针
temp = 0;
for(j=0;j "<< endl;
DataOutput();
}
void FIFO()
{
int i,j;
bool find;
int point;
int temp; // 临时变量
ChangeTimes = 0;
for(j=0;j=3的块,替换后计数值置1,
// 同时其它的块计数值加1 ,成了(1 3 2 ),见下面先进先出程序段
}
for(i=0;i M ) // 因为i是从0开始记,而M指的是个数,从1开始,所以i+1
{
//获得要替换的块指针
temp = 0;
for(j=0;j "<< endl;
DataOutput();
}
void LRU()
{
int i,j;
bool find;
int point;
int temp; // 临时变量
ChangeTimes = 0;
for(j=0;j M ) // 因为i是从0开始记,而BlockNum指的是个数,从1开始,所以i+1
{
//获得要替换的块指针
temp = 0;
for(j=0;j "<< endl;
DataOutput();
}
在将一个页面换出时,如果该页已被修改过,便须将该页重新写回到磁盘上;但如果该页未被修改过,则不必将它拷回磁盘。在改进型Clock算法中,除须考虑页面的使用情况外,还须在增加一个因素,即置换代价,这样页面换出时,既要是未使用过的页面,又要是未被修改过的页面。把同时满足这两个条件的页面作为首选淘汰的页面。由访问位A和修改位M可以组合成下面四种类型的页面:
1类(A=0,M=0):表示该页最近既未被访问,又未被修改,是最佳淘汰页。
2类(A=0,M=0):表示该页最近未被访问,但已被修改,并不是很好的淘汰页。
3类(A=1,M=0):表示该页最近已被访问,但未被修改,该页有可能在被访问。
4类(A=1,M=1):表示该页最近已被访问且被修改,该页可能再被访问。
oid LCLOCK(int num){
int j;
if(isInside2(num)){
cout<<"命中"<
内含有一般的clock算法运行过程
#include
const int DataMax = 64;
const int BlockNum = 32;
int DataShow[BlockNum][DataMax]; // 用于存储要显示的数组
bool DataShowEnable[BlockNum][DataMax]; // 用于存储数组中的数据是否需要显示
int Data[DataMax]; // 保存数据
int Block[BlockNum]; // 物理块
int count[BlockNum]; // 计数器
int N ; // 页面个数
int M;//最小物理块数
int ChangeTimes;
void DataCreate();
void DataOutput();
void FIFO(); // FIFO 函数
void Optimal(); // Optimal函数
void LRU(); // LRU函数
void Clock();
#define Q 999
using namespace std;
///*
int main(int argc, char* argv[])
{
DataCreate();// DataInput();
// FIFO();
// Optimal();
// LRU();
// return 0;
int menu;
while(true)
{
cout<>menu;
switch(menu)
{
case 1: FIFO();break;
case 2: Optimal();break;
case 3: LRU();break;
if(menu!=1&&menu!=2&&menu!=3) break;
}
}
}
//*/
void DataOutput()
{
int i,j;
for(i=0;i>M;
while(M > BlockNum) // 大于数据个数
{
cout<<"物理块数超过预定值,请重新输入:";
cin>>M;
}
cout<<"请输入页面的个数:";
cin>>N;
while(N > DataMax) // 大于数据个数
{
cout<<"页面个数超过预定值,请重新输入:";
cin>>N;
}
int p = 1;
int e = 4;
int m = 5;//处理4个页面后起始位置P+1
float t = 0.637;
float r;
int j = 0;
srand((int)time(NULL));//用time(0)的返回值当种子
for(int o=0;o<(N/m);o++)
{
for(int i=0;i=3的块,替换后计数值置1,
// 同时其它的块计数值加1 ,成了(1 3 2 ),见下面先进先出程序段
}
for(i=0;i M ) // 因为i是从0开始记,而M指的是个数,从1开始,所以i+1
{
//获得要替换的块指针
temp = 0;
for(j=0;j "<< endl;
DataOutput();
}
void Optimal()
{
int i,j,k;
bool find;
int point;
int temp; // 临时变量,比较离的最远的时候用
ChangeTimes = 0;
for(j=0;j M ) // 因为i是从0开始记,而BlockNum指的是个数,从1开始,所以i+1
{
//获得要替换的块指针
temp = 0;
for(j=0;j "<< endl;
DataOutput();
}
void LRU()
{
int i,j;
bool find;
int point;
int temp; // 临时变量
ChangeTimes = 0;
for(j=0;j M ) // 因为i是从0开始记,而BlockNum指的是个数,从1开始,所以i+1
{
//获得要替换的块指针
temp = 0;
for(j=0;j "<< endl;
DataOutput();
}
#include
#include
using namespace std;
#define M 2
#define Q 999
void DataCreate();
int const A = 4;//内存中存放的页面数
int count = 0;
int Inside[A];
int const PageCount =10;//总的页面数
int Page[PageCount];
int insert = 0;//先到先出置换算法fcfo中表示 当内存满的时候,新进入的页号放的位置
int suiji = 0; //随机置换算法randchange 当内存满的时候,新进入的页号放的位置
int state[A];//clock置换算法中,内存中的每个页面号对应的状态
int state2[A][M];// 二维数组,第一行第一列为访问位,第一行的第二列为修改位
double lost = 0.0;
void DataCreate()
{
int p = 1;
int e = 4;
int m = 5;//处理4个页面后起始位置P+1
float t = 0.637;
float r;
int j = 0;
srand((int)time(NULL));//用time(0)的返回值当种子
for(int o=0;o<(PageCount/m);o++)
{
for(int i=0;i>ch;
switch(ch){
case '1':{
lost = 0;
count = 0;
for(int m = 0; m < A; m++){
state[m] = 0;
}
for(int j = 0; j < A; j++){
Inside[j] = 0;
}
for(int i = 0; i < PageCount; i++){
cout<<"读入Page["<