提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
一、实验目的与要求
掌握分页存储管理的基本原理及分页存储管理中的地址变换过程,编制一个模拟地址变换过程的程序并能采用先进先出页面置换算法实现页面置换。
二、实验内容
1、复习分页存储管理的基本概念、基本原理及地址变换过程。
2、编制一个模拟地址变换过程并能进行缺页中断处理和页面置换的程序。
三、实验原理
在页式内存管理中,将程序空间分成大小相同的页,物理内存空间也分成大小相同的块,页的大小和块的大小一致。当程序装入内存准备运行时,逻辑上连续的页可以装入不连续的物理块中(当然也可以是连续的物理块)。程序执行时,为了正确地访问内存物理地址,需要使用页表,该表在创建进程由操作系统在内存特定区域创建,并根据当时的内存分配情况,动态地将程序中的各页装入内存的空闲块中,并填上页表。
在支持页式管理的系统中,为了加快地址映射速度,通常都把页表的全部或一部分放在快表中,由硬件自动完成地址映射过程。程序的逻辑地址可表示为:
P | W |
---|
其中P为页号,W为页内位移。假设块或页的大小为2nB(n为整数),则W的取值范围为0-2n-1。
给定一个逻辑地址LA,可以用两种方法得到P和W。
(1)P=LA>>n,W=LA&(2n-1) 速度快
(2)P=INT(LA/2n) ,W=LA % 2n 速度慢
当取得页号P 后查页表,能得到这一页装在内存中的块号B,也可以采用两种方法计算物理地址PA。
(1)PA=(B<<n)|W 速度快
(2)PA=B×2n+W
由于在CPU执行逻辑指令的速度远远高于执行算术指令的速度,所以都是采用方法一进行地址映射。
在进程执行的过程中,如果访问的页暂时不在内存,便产生缺页中断,由操作系统负责把所缺的页从外存调入内存,然后再重复执行产生缺页中断的指令,从而实现请求页式管理。
在调页的过程中,如果内存还有空闲的物理块时,当然可以给该进程追加内存分配;如果当内存中没有空闲的物理块时就需要淘汰一个当前在内存的“老页”,这个“老页”可以属于该进程本身,也可能属于别的进程。为了降低置换算法的复杂性而又不对其它进程产生影响,本实验采用前者,即局部置换方法。这样便可以在一个比较小的内存空间里运行一个较大的进程,从而实现虚拟存储器。
四、设计要求
由于在请求页式管理中采用部分装入技术,为了能在进程执行时正确地进行页面置换和地址映射,需要页表中增加若干项目,如状态位、访问位、修改位、外存地址等。本实验中进程长度为5页,实际只分配3个内存块,即0、1、2页在内存,4、5两页不在内存,在系统中采用FIFO置换算法。共有3个函数,分别为:
1、main()函数完成页表初始化和调度功能,公共变量和数据结构的定义,已在上面给出。
原始页表如下(*表示任意值),head=0即置换指针指向0页:
页号 | 内存块号 | 状态位 | 修改位 | 外存地址 |
---|---|---|---|---|
0 | 4 | 1 | 0 | 4 |
1 | 3 | 1 | 0 | 20 |
2 | 7 | 1 | 0 | 18 |
3 | * | 0 | 0 | 6 |
4 | * | 0 | 0 | 9 |
2、自行设计command()函数,该函数有2个形参,其中laddress为逻辑地址,write为命令代码,write=1表示写指令(修改该页内容),write=0表示读指令(不修改该页内容)。其工作流程见下图。
3、自行设计page_interrupt()函数,该函数为缺页中断处理函数,供command()函数调用,有一个形参lnumber,表示所缺的页号。其工作流程图,见下图。
五、实验过程
假设系统页长为1024B,依次输入“1 500”、“1 3500”,“1 4500”,“1 6000”观察运行结果并解释。
六、上机操作分析
1、 程序代码:
#include<iostream>
using namespace std;
#define m 3 //实际为该作业分配的主存块块数
#define page_length 5 //页表实际长度
struct //页表
{
int lnumber; //页号
int pnumber; //该页所在主存块的块号
int flag; //状态位,"1"表示该页在主存,"0"表示该页不在主存
int write; //修改位,"1"表示该页内容被修改过,"0"表示该页内容末修改过
int dnumber; //该页存在外存位置,即磁盘块号
}page[page_length];
int p[m]; //存放在主存中页的页号
int head; //主存中页号队列p首指针
void page_interrupt(int lnumber) //缺页中断处理函数
{
int n;
cout<<"页"<<lnumber<<"不在内存,发生缺页中断"<<endl;
//淘汰页
n=p[head];
p[head]=lnumber;
head=(head+1)%m;
if (page[n].write==1)
cout<<"将第"<<n<<"页写回磁盘第"<<page[n].dnumber<<"块中保存"<<endl;
//修改页表
page[n].flag=0;//第j页被换出,第j页存在标志改为"0"
page[lnumber].pnumber=page[n].pnumber;// 第lnumber页装入原来第j页所在的物理块
page[lnumber].flag=1;// 第lnumber页存在标志改为"1"
page[lnumber].write=0;//第lunmber页修改标志改为"0"
cout<<"淘汰主存块"<<page[n].pnumber<<"中的页"<<n<<",从磁盘第"<<page[lnumber].dnumber<<"块中调入页"<<lnumber<<endl;
}
void command(unsigned laddress,int write) //命令处理函数结束
{
unsigned paddress,inpageaddress,pnumber;
int lnumber;
lnumber=laddress>>10;//页号等于逻辑地址 /2的10次方
inpageaddress = laddress%0x0400;//页内地址利用位运算取后10位
label:
if(lnumber>=page_length) //判断页号是否越界
{
cout<<"超出页长,不存在该页"<<endl; //,显示出错误信息
return ;
}
else{
if(page[lnumber].flag==1)//判断该页是否在主存
{
pnumber=page[lnumber].pnumber;
paddress=pnumber<<10|inpageaddress;
cout<<"逻辑地址是"<<laddress<<",所对应的物理地址是"<<paddress<<endl;//在主存,转换成物理地址并显示
if(write==1) //判断该页内容是否被修改过
{
page[lnumber].write=1; // 修改过,页表中的修改位置为1
}
}
else
{ //不在主存,调用page_interrupt函数将所缺的页调入内存。
page_interrupt(lnumber);
goto label;
}
}
}
int main() //主函数
{
int write;
unsigned laddress;
//初始化页表,分配3个物理块。数据可改
page[0].lnumber=0;page[0].pnumber=4;page[0].flag=1;page[0].write=0;page[0].dnumber=4;
page[1].lnumber=1;page[1].pnumber=3;page[1].flag=1;page[1].write=0;page[1].dnumber=20;
page[2].lnumber=2;page[2].pnumber=7;page[2].flag=1;page[2].write=0;page[2].dnumber=18;
page[3].lnumber=3;page[3].pnumber=0;page[3].flag=0;page[3].write=0;page[3].dnumber=6;
page[4].lnumber=4;page[4].pnumber=0;page[4].flag=0;page[4].write=0;page[4].dnumber=9;
head=0; //开始指向p[0]
p[0]=0;p[1]=1;p[2]=2; //3个物理块中所放的页为0页、1页、2页
while(1)
{
cout<<"输入指令性质(1-写指令,0-读指令,其他--结束程序运行)和逻辑地址:";
cin>>write;
cin>>laddress;
if(write==0||write==1)
command(laddress,write);
else
break;
}
}
2、实验截图
3、结果解释
七、实验总结
本次实验,学习并掌握了分页存储管理的基本原理及分页存储管理中的地址变换过程,同时学会了编制一个模拟地址变换过程的程序并能采用先进先出页面置换算法实现页面置换。