文章目录
- 一、实验目的
- 二、实验内容
- 三、实验过程
- 四、结果测试
- 五、实验总结和说明
补录与分享本科实验,以示纪念。
一、实验目的
通过编写和调试请求页式存储管理的模拟程序以加深对请求页式存储管理方案的理解。
二、实验内容
页面淘汰算法可采用FIFO置换算法(或者其他置换算法),在淘汰一页时,判断它是否被改写过,如果被修改过,将它写回到外存上。
数据结构:
(1)虚地址结构
(2)页表结构
#define N 64 // 最大页数 64
#define PAGE_SIZE 1024 // 每页大小 1024
// 页表结构
struct {int lNumber; // 页号int pNumber; // 物理块号int dNumber; // 在磁盘上的位置int write; // 修改标志int flag; // 存在标志
} page[N];
(3)存放页号的队列 p[m]
,m
为分配给进程的内存块数。当装入一个新的页面时,将其页号存入数组。在模拟试验中,采用页面预置的方法。
请求页式存储管理算法的流程图如下:
三、实验过程
实验采用C++语言进行编写。
1、代码结构
int main() {// 创建页表,记录长度int len = createTable();// 打印页表printTable(len);// 获取内存块数int memoryBlocks = getMemoryBlocks(len);printTable(len);// 执行用户指令runUserCommand(len, memoryBlocks);return 0;
}
一共分为3个部分:创建页表、获取内存块、执行用户指令。
2、createTable():创建页表
/*** 创建页表* @return 页表长度*/
int createTable() {cout << "输入页表的信息,创建页表(输入 -1 则结束)\n";int input;int i = 0;while (true) {cout << "输入第 " << i << " 页的辅存地址:";cin >> input;if (input == -1) break;page[i].lNumber = i;page[i].pNumber = 0;page[i].dNumber = input;page[i].write = 0;page[i].flag = 0;i++;}return i;
}
3、getMemoryBlocks():获取内存块
/*** 获取主存块号* @param len 页表长度,作为主存块数上限* @return 主存块数*/
int getMemoryBlocks(int len) {cout << "输入主存块号,总数需小于 " << len << ",(-1 则结束):\n";int input;int i = 0;while (i < len) {cout << "第 " << i << " 个主存块号:";cin >> input;if (input == -1) break;page[i].pNumber = input;page[i].flag = 1;i++;}return i;
}
4、runUserCommand():执行用户指令
/*** 执行用户指令* @param tableLen 页表长度* @param blockNum 主存块数*/
void runUserCommand(int tableLen, int blockNum) {int modify = 0; // 用户第一个输入,是否修改int exitSig = 0; // 退出标记int input; // 接受用户输入int replace[blockNum]; // 循环队列实现 FIFOint in = 0; // 进队列的位置int out = 0; // 出队列的位置// 初始化循环队列for (int i = 0; i < blockNum; i++) {replace[i] = i;in++;in = in % blockNum;}// 进入操作循环while (true) {cout << "输入指令性质(1-修改,0-不修改,其他-结束运行)和逻辑地址:\n";cin >> input;// 第一个输入if (input == 1)modify = 1;else if (input == 0)modify = 0;elseexitSig = 1;// 输入逻辑地址int addr = 0;cin >> addr;// 求逻辑地址最大值int maxAddr = tableLen * PAGE_SIZE - 1;// 页不存在if (addr > maxAddr || input < 0) {cout << "不存在该页\n";continue;}// 得到逻辑地址所在页号int pageIndex = addr / PAGE_SIZE;// 记录页内偏移量,用于计算物理地址int left = addr % PAGE_SIZE;// 命中if (page[pageIndex].flag) {// 物理地址计算int physic = page[pageIndex].pNumber * PAGE_SIZE + left;cout << "逻辑地址是: " << addr << " 对应物理地址是:" << physic << "\n";// modify 为 1 时置写标记if (modify == 1)page[pageIndex].write = 1;}// 未命中else {// 打印用户要访问的页cout << "访问第 " << pageIndex << " 页不在内存,发生缺页中断\n";// 利用循环队列找出将被换出的页号 outNumint outNum = replace[out];// 出指针前进一位out++;out = out % blockNum;// 考虑将被换出的页有没有修改过,如果有须写回if (page[outNum].write == 1) {cout << "将 " << outNum << " 页写回磁盘第 " << page[outNum].dNumber << " 块\n";page[outNum].write = 0;}cout << "淘汰主存块 " << page[outNum].pNumber << " 中的页 " << outNum << ",从磁盘第 " << page[pageIndex].dNumber<< " 块中调入页 " << pageIndex << "\n";// 换入// 存在标记置 1,主存块号就是即将被换出的主存块号,如果有写标记则置写标记page[pageIndex].flag = 1;page[pageIndex].pNumber = page[outNum].pNumber;page[pageIndex].write = modify;// 刚换进的页面要进入循环队列replace[in] = pageIndex;in++;in = in % blockNum;// 换出// 标记位置 0,主存块号置 0page[outNum].flag = 0;page[outNum].pNumber = 0;// 计算物理地址int physic = page[pageIndex].pNumber * PAGE_SIZE + left;cout << "逻辑地址是:" << addr << " 对应物理地址是:" << physic << endl;}// 退出标记为 1,退出循环结束程序if (exitSig == 1) break;printTable(tableLen);}
}
5、printTable():打印页表
/*** 打印页表* @param len 页表长度*/
void printTable(int len) {cout << "页表内容:\n";for (int i = 0; i < len; i++) {cout << "page[" << i << "].lNumber = " << page[i].lNumber << " "<< "page[" << i << "].pNumber = " << page[i].pNumber << " "<< "page[" << i << "].flag = " << page[i].flag << "\n";}
}
四、结果测试
1、创建5个页表的进程,赋予3个内存块:
2、修改逻辑地址为1111的内容,其所在页号为1,页内偏移量为1111-1024=887。对应物理地址应改为3*1024+87:
3、修改逻辑地址为4200的内容,其不在进程的页表中,发生替换。这里因为被替换的第0页没有发生修改,因此不写回。
4、修改逻辑地址为3200的内容,其不在进程的页表中,发生替换。这里因为被替换的第1页发生了修改,因此写回。
5、读取逻辑地址为100的内容,其不在进程的页表中,发生替换。这里因为被替换的第5页没有发生修改,因此不写回。
可以看出,本次实验采用的替换算法为FIFO算法。
实验环境为Windows10中文家庭版,使用的编辑器为Clion。
五、实验总结和说明
实验采用的是最容易实现的FIFO页面替换算法,虽然实际应用中几乎不使用。本次实验的主体部分还是地址变换机构,对于页面替换仅仅是通过打印消息来代替其实现。在完成实验的同时,也巩固了有关方面的知识,大大加深了对请求页式存储管理方案的理解。
以上内容仅代表个人,代码纯属原创,如有错误请自行修改。