《操作系统》实验之虚拟存储管理

实验内容:

<一>

第一部分:模拟请求分页虚拟存储管理技术中的硬件地址变换和缺页中断的过程

提示:

1、             请求分页虚拟存储管理技术是把作业地址空间的全部信息存放在磁盘上,当作业被选中运行时,先把作业的开始几页装入主存并启动运行.为此,在为作业建立页表时,应说明哪些页已在内存,哪些页不在内存.

页表的格式如下:


页号


标志


主存块号


外存地址

其中,”标志”表示对应页是否已装入主存

0:表示对应页已装入主存

1:表示对应页未装入主存

“主存块号”表示该页对应的主存块的块号

“外存地址”表示该页所在的外存物理

2、             作业在执行时,指令中的逻辑地址指出参加运算操作数(或指令)地址中的页号和页内偏移量.硬件地址转换机构按页号查页表.

若该页的标志为”1”,则表示该页已在主存,从而找到该页对应的内存块号,根据关系式:

绝对地址=块号*块的长度+页内偏移量

     计算出欲访问的内存地址.由于页长为2的整次幂,所以只要将块号与页内偏移量相拼接,放入地址寄存器即可按照该地址取指令或取操作数,完成指定的操作.

若对应的页不在内存(即标志为0),则硬件产生缺页中断,转操作系统处理系统.根据页表中的”外存地址”,找到该页.再查内存分块表,找一个空闲块装入该页,修改页表和内存分块表,继续执行被中断的指令.

3、             设计一个”地址变换”程序,模拟硬件地址变换过程:

当访问的页在内存时,则形成绝对地址后,不去模拟指令的执行,而是输出被转换的地址;当访问的页不在内存时,则输出*该页(页号)不在内存,以表示产生了一次缺页中断;若地址非法,显示地址非法,并终止程序的运行.

假定内存的每块长度为128字节,现有一个只有七页的作业,其中第0页至第3页已经装入内存.该作业的页表如下:


页号


标志


内存块号


外存地址


修改值


0


1


5


011


1


1


1


8


012


1


2


1


9


013


0


3


1


1


021


0


4


0


022


5


0


023


6


0


121

作业执行的指令序列如下表:


操作


页号


单元号(八进制)


操作


页号


单元号(八进制)


+


0


070


移位


4


053


+


1


050


+


5


023


*


2


015



1


037



3


021



2


076



0


057


+


4


001


-


6


040



6


084

运行你设计的地址变换程序,显示或打印运行结果.因为只是模拟地址变换,并不模拟指令的执行,故不考虑上述指令的操作结果.

第二部分:采用先进先出(或LRU)算法,实现分页管理的缺页调度.

提示:

1、             在分页虚拟存储系统中,当硬件发出缺页中断时,若内存中已无空闲块,当采用FIFO算法时,则淘汰最先进入内存的页,若该页修改过,还要存入磁盘,然后,再把当前要访问的页装入该块,并修改表中的对应标志.

2、             当采用LRU算法时,则淘汰最近很少访问的页.

两算法均可采用一个数组或链表记录内存中页号的排序,每次将链首页淘汰.数组或链表中只包含页的虚页号─项信息,其它信息通过查页表得到.

实现:

实现的算法是LRU算法,模拟了硬件地址变换和缺页中断过程。

运行结果:

源代码:

  1 /*
  2  * 该程序使用了位图LRU置换算法
  3  */
  4
  5 #include <iostream>
  6 #include <string.h>
  7 #include <stdio.h>
  8 using namespace std;
  9
 10 //宏定义
 11 #define PAGE_TABLE_SIZE 10    //页表大小
 12 #define BITMAP_SIZE    10    //位图大小。块大小为128B,则内存大小:10*128B = 1280B
 13 #define BLOCK_SIZE 128    //块大小为128B
 14
 15 //结构体
 16 struct Page{    //页
 17     bool flag;                //标志,是否存入内存
 18     unsigned short blockNo;    //主存块号
 19     unsigned short addr;    //外村地址
 20     bool isMod;                //修改位
 21 };
 22
 23 struct JobWork{    //作业指令
 24     char operation[5];    //操作名称
 25     unsigned short PageNo;    //页号
 26     unsigned short UnitNo;    //单元号
 27 };
 28
 29 struct LRUNode{    //LRU链表节点
 30     unsigned short PageNo;    //页号
 31     LRUNode *next;        //指向下一个节点的指针
 32 };
 33
 34 //局部变量
 35 Page PageTable[PAGE_TABLE_SIZE];    //定义页表
 36 bool BitMap[BITMAP_SIZE];    //定义内存位图
 37 JobWork work[20];    //作业执行的指令序列
 38
 39 int PageTableNum;    //当前页表大小
 40 int workNum;        //当前作业指令集大小
 41
 42 LRUNode *LRUqueue;    //LRU(最近最久未使用算法)队列
 43
 44 //局部函数
 45 void Init();    //初始化,页表,位图等
 46 unsigned short GetAddr(unsigned short curPage,unsigned short UnitNo);    //输入 页号和页内偏移,得到绝对地址
 47 void Insert(unsigned short page);    //将最近使用的页插入到LRU队列中 或 在LRU队列中调整位置,使其始终保持最近最久未使用的页表节点在前面
 48 int FindFreeBlock();        //在内存中查找空闲块
 49 void DropLRUHead();            //丢弃掉LRU队列的第一个结点
 50 void DisplayPageTable();    //打印页表
 51 void DisplayLRUQueue();        //打印LRU队列
 52
 53 //主函数
 54 int main()
 55 {
 56     int i;
 57     Init();    //初始化
 58
 59     printf("初始页表:\n");
 60     DisplayPageTable();
 61     printf("\n");
 62     printf("初始LRU队列:\n");
 63     DisplayLRUQueue();
 64     printf("\n");
 65
 66     for(i=0;i<workNum;i++){    //模拟取指令
 67         printf("-------------------- 第%d条指令:%s -----------------------\n",i+1,work[i].operation);
 68         printf("取指令\n");
 69
 70         unsigned short curPage = work[i].PageNo;    //取该指令页号
 71         printf("取出页号:%d\n",curPage);
 72
 73         //判断地址是否非法
 74         if(curPage<0 || curPage>PageTableNum){    //页号非法
 75             printf(" 访问地址非法\n");
 76             return 0;
 77         }
 78         if(work[i].UnitNo<0 || work[i].UnitNo>=BLOCK_SIZE){    //页内偏移地址非法
 79             printf(" 访问地址非法\n");
 80             return 0;
 81         }
 82
 83         //判断该页是否在内存
 84         while( PageTable[curPage].flag!=1 ){
 85             printf(" 该页不在内存\n");
 86             printf(" 发出缺页中断\n");
 87             int freeBlock = -1;
 88             if( (freeBlock = FindFreeBlock())==-1 ){    //找内存中的空闲块。
 89                 printf(" 没有在内存中找到空闲块,调用LRU页面置换算法\n");
 90
 91                 unsigned short dropPage = LRUqueue->next->PageNo;    //被淘汰的页号
 92                 printf("  获得被淘汰的页号(%d)\n",dropPage);
 93
 94                 if( PageTable[dropPage].isMod==1 ){    //该页修改过
 95                     printf("   该页修改过,将该页调到磁盘");
 96                     PageTable[dropPage].isMod = 0;
 97                 }
 98
 99                 printf("  丢弃该页\n");
100                 PageTable[dropPage].flag = 0;
101                 DropLRUHead();    //丢弃掉LRU队列的第一个结点
102                 unsigned short dropBlock = PageTable[dropPage].blockNo;
103                 PageTable[dropPage].blockNo = -1;
104
105                 printf("  调进页(%d)到内存\n",curPage);
106                 Insert(curPage);
107                 PageTable[curPage].flag = 1;
108                 PageTable[curPage].blockNo = dropBlock;
109             }
110             else{    //找到空闲块
111                 //在页表中找到页号对应的页,修改标志位,赋给它内存块号
112
113                 printf("  在内存中找到空闲块,赋给给相应的页\n");
114                 PageTable[curPage].blockNo = freeBlock;
115                 PageTable[curPage].flag = 1;
116                 BitMap[freeBlock] = 1;
117                 Insert(curPage);
118             }
119
120         }
121         //该页在内存,形成并输出绝对地址
122         printf(" 该页在内存中\n");
123         unsigned short absAddr = GetAddr(curPage,work[i].UnitNo);    //输入 页号和页内偏移,得到绝对地址
124         Insert(curPage);    //调整内存页排序表(LRU队列)
125
126         if( strcmp(work[i].operation,"存")==0 ){
127             //如果是存指令
128             printf("  是存指令,置该页的修改位为 1\n");
129             PageTable[curPage].isMod = 1;
130         }
131
132         printf("绝对地址为:0x%04X\n",absAddr);
133         printf("\n");
134         printf("当前页表:\n");
135         DisplayPageTable();
136         printf("\n");
137         printf("当前LRU队列:\n");
138         DisplayLRUQueue();
139         printf("-----------------------------------------------------------\n");
140         printf("\n");
141
142     }
143     return 0;
144 }
145
146 //函数实现
147 void Insert(unsigned short page)    //将最近使用的页插入到LRU队列中 或 在LRU队列中调整位置,使其始终保持最近最久未使用的页表节点在前面
148 {
149     //查找链表,如果找到page,将代表该page的节点移到链表最后,说明刚刚使用过该页
150     LRUNode *p = LRUqueue;
151     while(p->next!=NULL){
152         if(p->next->PageNo==page){
153             //找到该节点,将其移动到LRU链表最后
154             LRUNode *t = p->next;
155             p->next = t->next;
156             while(p->next!=NULL){
157                 p = p->next;
158             }
159             p->next = t;
160             t->next = NULL;
161             return ;
162         }
163         p = p->next;
164     }
165     //如果没有找到page,则创建一个代表该page的节点,加入到LRU链表最后
166     if(p->PageNo!=page){
167         LRUNode* t = new LRUNode;    //创建节点
168         t->PageNo = page;
169         t->next = NULL;
170         p->next = t;
171     }
172     //最后一个节点是page的情况不用考虑,因为它本身就在最后,不用移位
173     return ;
174 }
175
176 void Init()    //初始化,页表,位图等
177 {
178     memset(PageTable,0,sizeof(PageTable));
179     memset(BitMap,0,sizeof(BitMap));
180     PageTableNum = 0;
181     workNum = 0;
182     LRUqueue = new LRUNode;
183     LRUqueue->next = NULL;
184
185     //初始化页表
186     PageTable[0].flag = 1;
187     PageTable[0].blockNo = 5;
188     PageTable[0].addr = 0x0011;
189     PageTable[0].isMod = 1;
190     Insert(0);
191     PageTableNum++;
192
193     PageTable[1].flag = 1;
194     PageTable[1].blockNo = 8;
195     PageTable[1].addr = 0x0012;
196     PageTable[1].isMod = 1;
197     Insert(1);
198     PageTableNum++;
199
200     PageTable[2].flag = 1;
201     PageTable[2].blockNo = 9;
202     PageTable[2].addr = 0x0013;
203     PageTable[2].isMod = 0;
204     Insert(2);
205     PageTableNum++;
206
207     PageTable[3].flag = 1;
208     PageTable[3].blockNo = 1;
209     PageTable[3].addr = 0x0021;
210     PageTable[3].isMod = 0;
211     Insert(3);
212     PageTableNum++;
213
214     PageTable[4].flag = 0;
215     PageTable[4].blockNo = -1;
216     PageTable[4].addr = 0x0022;
217     PageTable[4].isMod = 0;
218     PageTableNum++;
219
220     PageTable[5].flag = 0;
221     PageTable[5].blockNo = -1;
222     PageTable[5].addr = 0x0023;
223     PageTable[5].isMod = 0;
224     PageTableNum++;
225
226     PageTable[6].flag = 0;
227     PageTable[6].blockNo = -1;
228     PageTable[6].addr = 0x0121;
229     PageTable[6].isMod = 0;
230     PageTableNum++;
231
232     //初始化作业
233     strcpy(work[0].operation,"+");
234     work[0].PageNo = 0;
235     work[0].UnitNo = 070;
236     workNum++;
237
238     strcpy(work[1].operation,"+");
239     work[1].PageNo = 1;
240     work[1].UnitNo = 050;
241     workNum++;
242
243     strcpy(work[2].operation,"*");
244     work[2].PageNo = 2;
245     work[2].UnitNo = 015;
246     workNum++;
247
248     strcpy(work[3].operation,"存");
249     work[3].PageNo = 3;
250     work[3].UnitNo = 021;
251     workNum++;
252
253     strcpy(work[4].operation,"取");
254     work[4].PageNo = 0;
255     work[4].UnitNo = 057;
256     workNum++;
257
258     strcpy(work[5].operation,"-");
259     work[5].PageNo = 6;
260     work[5].UnitNo = 040;
261     workNum++;
262
263     strcpy(work[6].operation,"移位");
264     work[6].PageNo = 4;
265     work[6].UnitNo = 053;
266     workNum++;
267
268     strcpy(work[7].operation,"+");
269     work[7].PageNo = 5;
270     work[7].UnitNo = 023;
271     workNum++;
272
273     strcpy(work[8].operation,"存");
274     work[8].PageNo = 1;
275     work[8].UnitNo = 037;
276     workNum++;
277
278     strcpy(work[9].operation,"取");
279     work[9].PageNo = 2;
280     work[9].UnitNo = 076;
281     workNum++;
282
283     strcpy(work[10].operation,"+");
284     work[10].PageNo = 4;
285     work[10].UnitNo = 001;
286     workNum++;
287
288     strcpy(work[11].operation,"取");
289     work[11].PageNo = 6;
290     work[11].UnitNo = 074;
291     workNum++;
292
293     //将剩余的内存置为非空,即预先设定内存没有空闲位
294     int i;
295     for(i=0;i<BITMAP_SIZE;i++){
296         if(!BitMap[i])
297             BitMap[i] = 1;
298     }
299
300     return ;
301 }
302
303 unsigned short GetAddr(unsigned short curPage,unsigned short UnitNo)    //输入 页号和页内偏移,得到绝对地址
304 {
305     unsigned short absAddr = 0;    //结果
306
307     unsigned short curBlock = PageTable[curPage].blockNo;    //取块号
308     absAddr = curBlock*BLOCK_SIZE + UnitNo;
309
310     return absAddr;
311 }
312
313 int FindFreeBlock()        //在内存中查找空闲块
314 {
315     int i;
316     for(i=0;i<BITMAP_SIZE;i++){
317         if(BitMap[i]==0){    //找到空闲块,返回块号
318             return i;
319         }
320     }
321     return -1;    //没找到
322 }
323
324 void DropLRUHead()                    //丢弃掉LRU队列的第一个结点
325 {
326     LRUNode *t = LRUqueue->next;
327     LRUqueue->next = t->next;
328     free(t);
329 }
330
331 void DisplayPageTable()    //打印页表
332 {
333     int i;
334     printf("页号\t标志\t内存块号\t外存地址\t修改值\n");
335     for(i=0;i<PageTableNum;i++){
336         printf("%d\t",i);
337         printf("%d\t",PageTable[i].flag);
338         if(PageTable[i].blockNo==65535){
339             printf("-\t\t");
340         }
341         else{
342             printf("%d\t\t",PageTable[i].blockNo);
343         }
344         printf("0x%03x\t\t",PageTable[i].addr);
345         printf("%d\n",PageTable[i].isMod);
346     }
347     return ;
348 }
349
350
351 void DisplayLRUQueue()        //打印LRU队列
352 {
353     LRUNode *q = LRUqueue->next;
354     while(q!=NULL){
355         if(q->next==NULL)
356             printf("%d\n",q->PageNo);
357         else
358             printf("%d->",q->PageNo);
359         q = q->next;
360     }
361 }

Freecode : www.cnblogs.com/yym2013

时间: 2024-10-11 16:42:14

《操作系统》实验之虚拟存储管理的相关文章

操作系统(6)_虚拟存储管理_李善平ppt

image含各种段.

操作系统(八)—虚拟存储管理

虚拟存储管理 在前面总结了集中存储管理的刚上,要求作业的逻辑地址空间连续的存放主存储器 的某个区域中.当主存储器中没有足够大的区域是,则作业是无法装入的,或必须移动 某些作业后才能装入.是否有可能吧作业的连续逻辑地址空间分散到几个不连续的主存 区域,且仍能使作业正确执行呢? 若可行的话,则可充分利用主存空间有可减少移动所 花费的开销.不仅如此,还可采用虚拟存储管理技术,实现在较小的主存空间里运行较 大的作业. 虚拟存储管理:实现较小主存空间运行较大的作业. 一.页式存储管理:把主存储器分成大学相

操作系统实验指导书(完整版)

操作系统实验指导书 烟台大学计算机学院 操作系统课程组 2008-9-20 第一部分  操作系统上机指导   Linux操作系统环境: RedHat Enterprise Linux ES release 3 (Taroon Update 1) (2.4.21-9.EL) Red Flag Linux release 4.0 (HOT) (2.4)   登录到系统 常用命令练习: 用root账号(超级用户)注册,口令为computer(注意大小写).注册成功出现#号(超级用户系统提示符,普通用户

操作系统实验报告二

  操作系统实验报告二 姓名:许恺 学号:2014011329 日期:10月14日 题目1:编写线程池 关键代码如下: 1.Thread.h #pragma once #ifndef __THREAD_H #define __THREAD_H #include <vector> #include <string> #include <pthread.h> #pragma comment(lib,"x86/pthreadVC2.lib") using

操作系统实验报告四

操作系统实验4 题目1:编写页面内存的LRU替换算法 在实验3基础上考虑,如果当前分配的内存或保存页面的数据项已经被用完,这时再有新的网页请求,需要对已在内存中的网页数据进行替换,本实验内容需要使用LRU算法来对内存中的网页数据进行替换 题目2:编写页面内存的LFU替换算法 实现LFU(最少访问频率的页面替换)算法来管理内存页面 实验报告要求: 实验报告封面如下页所示. 按照题目要求,完成相关实验题目. 2.1报告中要包含完成此题目所查阅的一些关键技术材料.例如内存结构的设计.分配管理.回收方法

操作系统实验报告三

操作系统实验报告三 姓名:许恺 学号:2014011329 日期:2016.11.22 题目1:设计一段内存结构,能够缓存一定数量的网页,在客户端访问时,首先从内存中查找是否存在客户端访问的网页内容,如果存在,则直接从内存中将相应的内容返回给客户端:如果不存在,则从磁盘中将网页内容读入到内存,并返回给客户端   1.思想以及准备怎么做 在刚刚读完题目之后我的想法已经有了一点感觉要怎样做了,因为报告拖了比较久,所以老师也说过很多,好了直奔主题,首先要设计一段内存结构,用来缓存网页,其实就是做几个能

[操作系统实验lab3]实验报告

[感受]: 这次操作系统实验感觉还是比较难的,除了因为助教老师笔误引发的2个错误外,还有一些关键性的理解的地方感觉还没有很到位,这些天一直在不断地消化.理解Lab3里的内容,到现在感觉比Lab2里面所蕴含的内容丰富很多,也算是有所收获,和大家分享一下我个人的一些看法与思路,如果有错误的话请指正. [关键函数理解]: 首先第一部分我觉得比较关键的是对于一些非常关键的函数的理解与把握,这些函数是我们本次实验的精华所在,虽然好几个实验都不需要我们自己实现,但是这些函数真的是非常厉害!有多厉害,呆会就知

[Ubuntu]操作系统实验笔记

前些日子为了更新Ubuntu到14.04这个LTS版本,连带着把Windows也重新安装了一遍.懒得再安装虚拟机了,尝试一下在Ubuntu14.04这个64位系统里做操作系统实验咯. 1.安装交叉编译器 第一个要解决的问题就是交叉编译器,材料里提供的是x86平台上的交叉编译器.按道理来说64位系统应该是支持32程序的呢.试一下. 先不吐槽说说明文档里面的代码了.首先要解决的是各种权限问题.sudo su似乎不能全部搞定. 经过一堆权限不够的提示后我对安装已经基本没有信心了. 2.安装gxemul

0311 了解和熟悉操作系统实验

实验0.了解和熟悉操作系统实验 专业:商业软件工程2班   姓名:王俊杰  学号:201406114252 一.        实验目的 (1)掌握操作系统的定义和概念: (2)了解各类操作系统的发展历史: 二.        实验内容和要求 使用网络搜索了解各类计算机操作系统的知识,并整理成一篇文档. 实验方法.步骤及结果测试 了解和掌握内容包括: 计算机操作系统的定义和概念: 操作系统是方便用户.管理和控制计算机软硬件资源的系统软件(或程序集合). 从用户角度看,操作系统可以看成是对计算机硬