Nachos 实验11 设计并实现用户空间的虚拟内存管理-上
- 格式:doc
- 大小:49.50 KB
- 文档页数:17
OS实验指导四——虚拟存储器管理————————————————————————————————作者:————————————————————————————————日期:2《操作系统》实验指导四开课实验室:A207、A209 2015/11/23 、2015/11/24实验类型设计实验项目(四)虚拟存储器管理实验实验学时 4一、实验目的设计一个请求页式存储管理方案,并编写模拟程序实现。
二、设备与环境1. 硬件设备:PC机一台2. 软件环境:安装Windows操作系统或者Linux操作系统,并安装相关的程序开发环境,如C \C++\Java 等编程语言环境。
三、实验要求1) 上机前认真复习页面置换算法,熟悉FIFO算法和LRU页面分配和置换算法的过程;2) 上机时独立编程、调试程序;3) 根据具体实验要求,完成好实验报告(包括实验的目的、内容、要求、源程序、实例运行结果截图)。
四、实验内容1、问题描述:设计程序模拟FIFO和LRU页面置换算法的工作过程。
假设内存中分配给每个进程的最小物理块数为m,在进程运行过程中要访问的页面个数为n,页面访问序列为P1, … ,Pn,分别利用不同的页面置换算法调度进程的页面访问序列,给出页面访问序列的置换过程,并计算每种算法缺页次数和缺页率。
2、程序具体要求如下:编写程序用来模拟虚拟页式存储管理中的页面置换要求:1)快表页面固定为4块2)从键盘输入N个页面号3)输出每次物理块中的页面号和缺页次数,缺页率4)实现算法选择3、程序流程图3、源程序参考:(1)FIFO 算法部分#include "stdio.h"#define n 12#define m 4void main(){int ym[n],i,j,q,mem[m]={0},table[m][n];char flag,f[n];printf("请输入页面访问序列\n ");for(i =0;i <n;i ++) scanf("%d ",&ym[i]);printf("\n ");for(i =0;i <n;i ++) //查页表,看是否缺页{输入页面取访问查是否是置缺页标按不同算调入所访否q=0;while((ym[i]!=mem[q])&&(q!=m)) q++;if(q==m) flag='*'; //缺页,则置标志flag为‘*’else flag='';if(flag=='*'){for(j=m-1;j>0;j--) //淘汰最先调入的页面调入当前访问的mem[j]=mem[j-1];mem[0]=ym[i];}for(j=0;j<m;j++)table[j][i]=mem[j];f[i]=flag;}printf("输出结果为下表(0代表为空,*代表有缺页):\n");for(i=0;i<m;i++){for(j=0;j<n;j++)printf("%3d",table[i][j]);printf("\n");}for(i=0;i<n;i++)printf("%3c",f[i]);}(2)LRU算法#include "stdio.h"#define n 12#define m 4void main(){int ym[n],i,j,q,mem[m]={0},table[m][n];char flag,f[n];printf("请输入页面访问序列\n");for(i=0;i<n;i++)scanf("%d",&ym[i]);printf("\n");for(i=0;i<n;i++) //查页表,看是否缺页{q=0;while((ym[i]!=mem[q])&&(q!=m)) q++;if(q==m) flag='*'; //缺页,则置标志flag为‘*’else flag=' ';for(j=q;j>0;j--)mem[j]=mem[j-1];mem[0]=ym[i];for(j=0;j<m;j++)table[j][i]=mem[j];f[i]=flag;}printf("输出结果为下表(0代表为空,*代表有缺页):\n");for(i=0;i<m;i++){for(j=0;j<n;j++)printf("%3d",table[i][j]);printf("\n");}for(i=0;i<n;i++)printf("%3c",f[i]);}4.测试用例:见第四章课后习题第26题(P159),(注意用比较的方式对程序的运行结果加以分析,比如令M=3或M=4时,结果各有什么不同。
实习五虚拟存储器实验报告一、实验目的本次虚拟存储器实验旨在深入理解计算机系统中虚拟存储器的工作原理和机制,通过实际操作和观察,掌握虚拟存储器的相关概念和技术,包括页式存储管理、地址转换、页面置换算法等。
同时,培养我们的实践能力和问题解决能力,为今后学习和工作中涉及到的计算机系统相关知识打下坚实的基础。
二、实验环境本次实验使用的操作系统为 Windows 10,开发工具为 Visual Studio 2019,编程语言为 C++。
三、实验原理1、虚拟存储器的概念虚拟存储器是一种利用硬盘等辅助存储器来扩充主存容量的技术。
它将程序和数据按照一定的页面大小划分,并在需要时将页面从硬盘调入主存,从而实现了使用有限的主存空间运行较大规模的程序。
2、页式存储管理页式存储管理将主存和辅存空间都划分为固定大小的页面。
程序的地址空间被分成若干页,主存也被分成相同大小的页框。
通过页表来记录页面和页框的对应关系,实现地址转换。
3、地址转换当 CPU 执行指令时,给出的是逻辑地址。
通过页表将逻辑地址转换为物理地址,才能在主存中访问相应的数据。
4、页面置换算法当主存空间不足时,需要选择一个页面换出到硬盘,以腾出空间调入新的页面。
常见的页面置换算法有先进先出(FIFO)算法、最近最少使用(LRU)算法等。
四、实验内容与步骤1、设计并实现一个简单的页式存储管理系统定义页面大小和主存、辅存的容量。
实现页表的数据结构,用于记录页面和页框的对应关系。
编写地址转换函数,将逻辑地址转换为物理地址。
2、实现页面置换算法分别实现 FIFO 和 LRU 页面置换算法。
在页面调入和调出时,根据相应的算法选择置换的页面。
3、测试和分析实验结果生成一系列的访问序列,模拟程序的运行。
统计不同页面置换算法下的缺页次数和命中率。
分析实验结果,比较不同算法的性能。
五、实验过程与结果1、页式存储管理系统的实现我们将页面大小设置为 4KB,主存容量为 16MB,辅存容量为 1GB。
计算机科学与技术学院实验报告:10实验题目:具有二级索引的文件系统姓名:李威日期:2013-12-1 学号:201100300259Email:sduliwei@实验目的:Nachos的文件系统中保存文件内容所在扇区索引的“文件头“目前只占用一个扇区,为了可以使Nachos文件系统创建较大的文件,将”文件头”扩大到两个扇区,也就是实现二级索引。
硬件环境:软件环境:Linux操作系统,Nachos操作系统实验步骤:1,通过实验5的扩展文件大小的实验,了解了nachos 系统的对文件系统的管理。
本次实验的目的主要是扩大Nachos系统可以创建的文件的大小,使用两个扇区来保存文件头的信息。
为了达到这个目的,首先了解nachos 自带的文件系统的文件头的结构:保存在一个扇区中,第一个int保存了文件的字节数(numBytes),第二个int保存了使用的扇区数(numSectors),第三个数据结构是文件所在的各个扇区号(dataSectors[NumDiresct])。
也就是说,Nachos系统采用的是索引式的文件管理方式。
因而,要实现nachos文件系统的二级索引,可以使第一个索引节点(也就是原有的文件头那个扇区)的dataSectors数组的最后一个元素保留第二个索引节点(也就是第二个扇区)的引用(也就是扇区号)。
如果文件大小不超过一个索引节点可以保留的内容,则这个最后一个元素的值为-1。
2,通过分析可知,需要修改中的内容。
代码如下:boolFileHeader::Allocate(BitMap *freeMap, int fileSize){numBytes = fileSize;numSectors = divRoundUp(fileSize, SectorSize);if (freeMap->NumClear() < numSectors)return FALSE; // not enough space/*如果文件大小超过索引节点中保存扇区号的数目,则返回false*/else if(NumDirect + NumDirect2 <= numSectors)return FALSE;//the filesys cannot support such big file/*toNextNode 是保留第二个索引节点的扇区号*/int toNextNode=NumDirect-1; //toNextNode is the Sector number of the second node of the filehd//if the second node is not needed, then dataSector[toNextNode]=-1if(numSectors < toNextNode){for (int i = 0; i < numSectors; i++)dataSectors[i] = freeMap->Find();//为文件分配扇区dataSectors[toNextNode] = -1;}//If the numSectors excends the rage of dataSectors,else{for (int i = 0; i < toNextNode; i++)dataSectors[i] = freeMap->Find();dataSectors[toNextNode] = freeMap->Find();//找一个空闲的扇区,作为第二个扇区,索引节点//this is the content,i.e.filehdr of the allocated sectors, of the second nodeint dataSectors2[NumDirect2];for (int i = 0; i < numSectors - NumDirect; i++)dataSectors2[i] = freeMap->Find();//为文件分配扇区//the fefault synchDisk->WriteSector do not include the second node//so write back the new build nodesynchDisk->WriteSector(dataSectors[toNextNode], (char *)dataSectors2); }return TRUE;/*revised*/}voidFileHeader::Deallocate(BitMap *freeMap){/*toNextNode 是保留第二个索引节点的扇区号*/int toNextNode= NumDirect - 1;// test if has the second nodeif(dataSectors[toNextNode]==-1){for (int i = 0; i < numSectors; i++){ASSERT(freeMap->Test((int) dataSectors[i])); // ought to be marked!freeMap->Clear((int) dataSectors[i]);}}//has a second node, then find it, then clean the bitmap, thenelse{//clear the first n-1 bit,remain the toNextNodeint i=0;for ( ; i < toNextNode; i++){ASSERT(freeMap->Test((int) dataSectors[i])); // ought to be marked!freeMap->Clear((int) dataSectors[i]);}int dataSectors2[NumDirect2];synchDisk->ReadSector(dataSectors[toNextNode], (char *)dataSectors2);freeMap->Clear((int) dataSectors[toNextNode]);//clear the toNextNodefor( ; i < numSectors; i++)freeMap->Clear((int) dataSectors2[i-toNextNode]);//toNextNode==the number of filehdr item }}intFileHeader::ByteToSector(int offset){ASSERT(offset<=numBytes);/*toNextNode 是保留第二个索引节点的扇区号*/int toNextNode = NumDirect - 1; //test if offset excedes the first nodeif(offset / SectorSize < toNextNode)return(dataSectors[offset / SectorSize]);else{int dataSectors2[NumDirect2];synchDisk->ReadSector(dataSectors[toNextNode], (char *)dataSectors2);return (dataSectors2[offset / SectorSize - toNextNode]);}}voidFileHeader::Print(){/*revised*/int i, j, k;/*toNextNode 是保留第二个索引节点的扇区号*/int toNextNode = NumDirect - 1;char *data = new char[SectorSize];//test if there is a second nodeif(dataSectors[toNextNode] == -1){printf("FileHeader contents. File size: %d. File blocks:\n", numBytes); for (i = 0; i < numSectors; i++)printf("%d ", dataSectors[i]);printf("\nFile contents:\n");for (i = k = 0; i < numSectors; i++) {synchDisk->ReadSector(dataSectors[i], data);for (j = 0; (j < SectorSize) && (k < numBytes); j++, k++) {if ('\040' <= data[j] && data[j] <= '\176') // isprint(data[j])printf("%c", data[j]);elseprintf("\\%x", (unsigned char)data[j]);}printf("\n");}}// If there is a secondary index,// first read in the dataSectors2 from the Disk.// Then, deallocate the data blocks for this file.// At last, deallocate the block that dataSector2 locates.else{int dataSectors2[NumDirect2];synchDisk->ReadSector(dataSectors[toNextNode], (char *)dataSectors2);//1, print the filedre itemsprintf("FileHeader contents. File size: %d. File blocks:\n", numBytes);for (i = 0; i < toNextNode; i++)printf("%d ", dataSectors[i]);for(; i < numSectors; i++)printf("%d ", dataSectors2[i - toNextNode]);printf("\nFile contents:\n");//2,print the content of the first node pointedfor (i = k = 0; i < toNextNode; i++) {synchDisk->ReadSector(dataSectors[i], data);for (j = 0; (j < SectorSize) && (k < numBytes); j++, k++) {if ('\040' <= data[j] && data[j] <= '\176') // isprint(data[j])printf("%c", data[j]);elseprintf("\\%x", (unsigned char)data[j]);}printf("\n");}//3,print the content of the second node pointedfor( ; i < numSectors; i++) {synchDisk->ReadSector(dataSectors2[i - toNextNode], data);for (j = 0; (j < SectorSize) && (k < numBytes); j++, k++) {if ('\040' <= data[j] && data[j] <= '\176') // isprint(data[j])printf("%c", data[j]);elseprintf("\\%x", (unsigned char)data[j]);}printf("\n");}}delete [] data;/*revised*/}boolFileHeader::AppSectors(BitMap *freeMap, int appFileSize){/*revised*/if(appFileSize <= 0)return false;int restFileSize = SectorSize * numSectors - numBytes;if(restFileSize >= appFileSize){numBytes += appFileSize;return true;}else{int moreFileSize = appFileSize - restFileSize;if(freeMap->NumClear()< divRoundUp(moreFileSize, SectorSize))return FALSE;else if(NumDirect + NumDirect2 <= numSectors + divRoundUp(moreFileSize, SectorSize)) return FALSE;int i = numSectors;numBytes += appFileSize;numSectors += divRoundUp(moreFileSize, SectorSize);/*toNextNode 是保留第二个索引节点的扇区号*/int toNextNode = NumDirect-1; //test if has the second nodeif(dataSectors[toNextNode] == -1){//test if need the second nodeif(numSectors < toNextNode)for( ; i < numSectors; i++)dataSectors[i] = freeMap -> Find();//need the second nodeelse{for( ; i< toNextNode ; i++)dataSectors[i]= freeMap ->Find();dataSectors[toNextNode] = freeMap ->Find();int dataSectors2[NumDirect2];for ( ; i < numSectors ; i++)dataSectors2[i - toNextNode] = freeMap->Find();synchDisk->WriteSector(dataSectors[toNextNode], (char *)dataSectors2);}}/** If before appending, there is already a secondary index*///First read the dataSectors2 from the Disk.//Then, append the file size.//At last, write back the secondary index block into the sector,else{int dataSectors2[NumDirect2];synchDisk->ReadSector(dataSectors[toNextNode], (char *)dataSectors2);for( ; i < numSectors; i++)dataSectors2[i-toNextNode] = freeMap -> Find();//the var toNextNode==the number of int that synchDisk->WriteSector(dataSectors[toNextNode], (char *)dataSectors2);//the fefault synchDisk}}return TRUE;/*revised*/}运行结果:首先运行命令 ./nachos –f 格式化Nachos磁盘然后运行 ./nachos –ap test/big big 若干次,知道出现提示,文件太大不能再追究为止。
虚拟存储器的实现方法
虚拟存储器是操作系统中的一个重要概念,用于扩展计算机的物理内存。
虚拟存储器的实现方法可以基于以下几种技术:
1. 分页机制:将物理内存和虚拟内存划分为固定大小的页,并将虚拟内存中的页面映射到物理内存中的页。
通过页面替换算法(如最近最久未使用算法)将虚拟内存中的页面从磁盘中加载到物理内存中的空闲页面,从而实现虚拟内存的扩展。
2. 分段机制:将程序按照逻辑结构划分为不同的段,每个段有不同的长度,可以动态地加载到物理内存中。
通过段表将虚拟内存中的段映射到物理内存中的段,并根据需要进行加载和替换。
3. 页面置换算法:虚拟存储器在物理内存空间不足时,需要选择一些页面置换出物理内存,从而将新的页面加载进来。
常见的页面置换算法包括FIFO(先进先出)、LRU(最近最久未
使用)、LFU(最不经常使用)等。
4. 页面回写机制:当页面被替换出物理内存时,如果其中的数据已被修改,需要将数据回写到磁盘中,以保持数据的一致性。
5. 页面预调度机制:根据程序运行的局部性原理,预测将来可能访问的页面,并提前将这些页面加载到物理内存中,减少缺页异常的发生。
需要注意的是,虚拟存储器的实现方法是操作系统的核心功能
之一,具体的实现方式会受到硬件架构、操作系统设计等多个因素的影响。
不同的操作系统可能会采用不同的实现方法来满足自身的需求。
虚拟内存设置方法虚拟内存是计算机系统中的一种内存管理技术,用于将内存中的数据存储到硬盘上,以便释放物理内存空间。
在Windows操作系统中,可以通过以下步骤设置虚拟内存:1. 打开控制面板:可以通过点击开始菜单,然后在搜索框中输入"控制面板"来打开控制面板。
2. 进入系统和安全选项:在控制面板中,点击"系统和安全"选项。
3. 进入系统选项:在系统和安全页面中,点击"系统"选项。
4. 进入高级系统设置:在系统选项页面中,点击"高级系统设置"链接。
5. 进入高级选项卡:在系统属性对话框中,点击"高级"选项卡。
6. 修改虚拟内存设置:在高级选项卡中,点击"性能"部分下的"设置"按钮。
7. 进入虚拟内存设置:在性能选项对话框中,点击"高级"选项卡。
8. 修改虚拟内存大小:在虚拟内存选项中,点击"更改"按钮。
9. 取消自动管理虚拟内存:在虚拟内存对话框中,取消选中"自动管理所有驱动器的分页文件大小"复选框。
10. 设置虚拟内存大小:选择要修改的驱动器,并选择"自定义大小"选项。
然后,输入所需的初始大小(以MB为单位)和最大大小(以MB为单位)。
11. 保存设置:点击"设置"按钮后,系统会提示重新启动计算机以应用新的设置。
请注意,虚拟内存的大小应根据计算机的硬件配置和使用需求进行设置。
通常,建议将虚拟内存的初始大小设置为物理内存的1.5倍,并将最大大小设置为物理内存的3倍。
然而,具体的设置可能需要根据实际情况进行调整。
计算机科学与技术学院2009-2010 学年第一学期《操作系统》课程设计题目: Nachos线程模块分析班级: 070341 B 学号: 070341221 姓名:阮琳琳教师:杨志娴成绩:1. 题目分析本次课程设计中,我将遵循课本上进程部分的章节组织来分析Nachos中线程模块。
我想这样会使分析的思路更加清晰,系统性和理论性更强。
分析目的:通过阅读nachos代码,了解一个最基本的操作系统是如何工作运转起来的。
结合书本上的知识,理解nachos中的源码,并使在书本上学到的知识得到巩固。
以使我对操作一同这门课有更深入的理解。
Nachos相关知识概述一、Nachos的线程管理Nachos广泛采用线程的概念,是多线程操作系统。
线程是Nachos处理机调度的单位,在Nachos中线程分成两类,一类是系统线程。
所谓系统线程是只运行核心代码的线程,它运行在核心态下,并且占用宿主机的资源,系统线程共享Nachos操作系统本身的正文段和数据段;一个系统线程完成一件独立的任务。
Nachos的设计者认为,教授并发性的最好方法是让读者能够直观地看到程序的并发行为。
Nachos的另一类线程同Nachos中的用户进程有关。
Nachos中用户进程由两部分组成,核心代码部分和用户程序部分。
用户进程的进程控制块是线程控制块基础上的扩充。
每当系统接收到生成用户进程的请求时,首先生成一个系统线程,进程控制块中有保存线程运行现场的空间,保证线程切换时现场不会丢失。
该线程的作用是给用户程序分配虚拟机内存空间,并把用户程序的代码段和数据段装入用户地址空间,然后调用解释器解释执行用户程序;由于Nachos模拟的是一个单机环境,多个用户进程会竞争使用Nachos唯一的处理机资源,所以在Nachos用户进程的进程控制块中增加有虚拟机运行现场空间以及进程的地址空间指针等内容,保证用户进程在虚拟机上的正常运行。
系统线程竞争使用宿主机的CPU资源,而用户进程的用户程序部分竞争使用的是虚拟机的CPU和寄存器。
win11虚拟内存设置方法
一般来说,如果我们电脑的内存不足,可以通过设置虚拟内存的方式,来添加一定的电脑内存,暂时解决我们内存不足的问题,可以帮助我们玩游戏、使用软件时更加方便。
win11怎么设置虚拟内存:1、首先我们点击下发任务栏中的开始菜单。
2、然后点击最上方的搜索框,输入并打开“高级系统设置”。
3、接着在其中找到性能下的“设置”。
4、然后点击上方“高级”再点击虚拟内存中的“更改”。
5、然后取消勾选“自动管理所有驱动器的分页文件大小”,再勾选“自定义大小”。
6、接着在其中设置初始大小和最大值,一般来说设置为真实内存的1.5-2.5倍,再点击“确定”即可。
虛擬記憶體管理Demand PagingCopy--on on--write, SwappingCopy頁替換演算法, 欄配置演算法Thrashing記憶體對映檔案虛擬記憶體(virtual memory) 使行程執行於虛擬位址空間的技術次級儲存體虛擬記憶體由四部分組成, 通常使用分頁與置換來實作 虛擬位址空間(Virtual address space)行程所看到的位址空間→邏輯位址空間記憶體對映→分頁表實體記憶體■次級儲存體(硬碟) 優點具有分頁的所有優點允許行程不必完全存在實體記憶體中而執行 可允許執行需求超過實體記憶體的行程Demand Paging行程執行時只有在需要讀寫或執行某一頁的時候才把該頁置換進來範例1111--1頁的無效位元標示頁是否存在實體記憶體中,否則須載入分頁錯誤(Page fault)參考到無效頁時中斷至作業系統由磁碟載入存取時間8mson--write)(Copy--on寫入時複製(Copyfork時並不複製資料分頁,直到寫入時才複製分頁替換(Swapping) 所有記憶空間都已被使用所有記憶空間都已被使用, , 就必須替換到硬碟就必須替換到硬碟分頁替換 如果沒有空白欄可用如果沒有空白欄可用, , 即替換未使用的欄即替換未使用的欄儲存未被需求頁儲存未被需求頁, , 載入需求頁載入需求頁, , 更改分頁表更改分頁表頁替換與欄配置Demand Paging 下行程不須分配所有的記憶體 硬碟I/O 需要時間: 讀取8ms, 傳輸50us減少分頁錯誤→改善演算法頁替換演算法--FIFO替換最早替換過的頁→Belady's anomaly頁替換演算法--最佳頁替換 把未來最長時間之內不會被用到的那一頁替換掉→必須預知哪種情況最佳頁替換演算法--LRU替換近來最少使用(Least (Least--Recently Recently--Used)的頁額外的堆疊表, 將最近參考的頁置於堆疊頂端→缺少硬體支援很難實現頁替換演算法--第二次機會替換法 Intel CPU 分頁功能支援Accessed (參考位元) 讀取該頁則設為1Dirty (修改位元) 修改該頁則設為1(0, 0) 最近未使用也未被修改→最佳替換頁(0, 1) 最近末使用但曾被修改→需要寫入磁碟, 才能替換(1, 0) 最近被使用但未修改→設A 為0, 第二次機會(1, 1) 最近被使用且被修改→最有可能再被使用, 非必要不替換頁替換演算法--頁緩衝法 頁緩衝區頁被修改且需要替換時, 由系統接管, 行程可以不必等待頁的寫入分頁裝置閒置時,就選出緩衝區的頁寫入磁碟中, 該頁Dirty 位元重置為0緩衝區中的頁被參考到緩衝區中的頁被參考到, , 即歸還給行程即歸還給行程欄配置演算法每個行程的最少量有效減少分頁錯誤的最低數目每個行程可配置的最大量實體記憶體扣除作業系統所剩都可配置行程間分配行程有需要就必須配置Realtime考量是否可替換其他行程的頁? ? Realtime平均分配, 或依分頁錯誤頻率, CPU 使用率,優先權等等分配分頁錯誤頻率太高→行程需要更多的欄→配置更多欄或避免替換太低→行程擁有太多欄→優先替換輾轉現象(Thrashing)CPU 使用率降低→執行新行程→替換原有行程的頁→更多的分頁錯誤→CPU使用率更降低→…預先載入分頁(Prepaging Prepaging)) 預先載入行程所預先載入行程所需求分頁附近的分需求分頁附近的分頁頁硬碟載入分頁時硬碟載入分頁時, , 傳輸時間傳輸時間<< << 搜尋時間搜尋時間行程的分頁需求通常有區域性 行程行程開始執行開始執行時常出現時常出現大量的分頁大量的分頁錯誤錯誤記憶體對映檔案(memory mapping file)允許部份的虛擬位址空間邏輯上連接到檔案。
操作系统管理-虚拟存储器-实验报告-代码7页一、实验目的学习操作系统中虚拟存储器的概念,掌握虚拟存储器的实现思路和方式。
二、实验要求在C语言环境下,实现基于分页机制的虚拟存储和页表管理。
三、实验内容1.实现一个虚拟存储器,其中分页大小为4KB,虚拟地址空间大小为4GB(每个进程可以使用的虚拟地址空间)。
物理内存大小为512MB,即实际内存中有128个物理页面。
2.实现页表管理,将虚拟地址映射到物理地址。
3.实现页面替换算法,当物理内存不足时,需要将某些页面从内存中置换出来。
4.实现程序的运行,能够根据页面缺失率输出性能参数。
四、实验步骤1.确定程序设计思路和数据结构。
2.实现虚拟存储器和页表管理。
3.实现页面替换算法。
五、实验代码及解析对于程序设计思路,首先需要确定虚拟存储器和物理内存的大小,以及页面大小。
虚拟存储器大小默认为4GB,物理内存大小为512MB,页面大小为4KB。
其次,需要设计页表数据结构。
页表可以使用一个二维数组表示,其中第一维表示页表项,第二维表示页内地址。
页表项有四个字段,分别为标志位(是否在内存中)、页框号(页面所在的物理页框号)、保护(页面的读写权限)、计数(页面使用情况的计数器)。
第三,需要设计页面替换算法。
本程序采用最近最少使用算法(LRU)作为页面替换算法,当物理内存不足时,选择使用最近最少使用的页面进行替换。
#define PAGE_SIZE 4096 // 页面大小#define VIRTUAL_MEM_SIZE 4 * 1024 * 1024 * 1024 // 虚拟存储器大小#define PHYSICAL_MEM_SIZE 512 * 1024 * 1024 // 物理内存大小#define PAGE_NUM (VIRTUAL_MEM_SIZE / PAGE_SIZE) // 页面总数#define PHYSICAL_PAGE_NUM (PHYSICAL_MEM_SIZE / PAGE_SIZE) // 物理页面数struct page_table_entry {int present; // 是否在内存中(1为在,0为不在)int page_frame; // 页面所在的物理页框号int protect; // 页面的读写权限int count; // 页面使用情况的计数器}struct page_table_entry page_table[PAGE_NUM][PAGE_SIZE]; // 页表虚拟存储器和页表管理需要掌握的是页表的相关数据结构,还有一个重要的点,就是如何将虚拟地址映射到物理地址。
14 实验目的 在未实现用户空间的虚拟内存管理之前,Nachos系统在运行一个用户进程的时候,需要将程序在运行时可能会用到的所有信息都拷贝到mainMemory中去。这样,因为mainMemory 的大小的限制,一些较大的文件可能无法执行;而相对应的,一些程序中可能包含着大量在执行过程中极少或根本不会被访问的数据,这些数据却又长期占据了内存的资源。本次试验的目的:
整体理解Nachos系统的组织结构。 设计并实现用户空间的虚拟内存管理。 实验环境 Linux操作系统,Nachos操作系统 实验分析 此次实验是在实验7-8——Extension of AddrSpace and System Calls Exec()的基础上更改的。实验的目录并没有在系统已有的vm目录下进行,而是将实验目录lab7-8更名为lab11,目的是使用lab7-8目录下的Makefile文件。在本次实验的过程中,发现并更改了实验7-8的一些疏漏之处。
为了说明方便,首先澄清一下基本概念和数据结构: 用bitmap做物理地址分配
图1 存取关系图 页表 class TranslationEntry { public: int virtualPage; // The page number in virtual memory. // 对应于图1中的虚页 int physicalPage; // The page number in real memory (relative to the // start of "mainMemory" // 对应于图1中的物理页 14
bool valid; // If this bit is set, the translation is ignored. // (In other words, the entry hasn't been initialized.) bool readOnly; // If this bit is set, the user program is not allowed // to modify the contents of the page. bool use; // This bit is set by the hardware every time the // page is referenced or modified. bool dirty; // This bit is set by the hardware every time the // page is modified. int inFileAddr; //The address of this segment of data in the file. //对于vmcode、vminitData,inFileAddr代表在源文件中的addr //对应于图1中的linux系统下的文件*.noff. //对于vmuninitData、vmuserStack,inFileAddr代表在SWAP文件中的位置 PageType type; //The type of this entry. //标明页中数据的类型 }; 为了实现虚拟内存的页置换,在以上类中增加一个该页在文件中块偏移量inFileAddr和当前页存储的数据的类型的type。
其中type的类型PageType定义为枚举类型,写在文件translate.h中。 enum PageType {vmcode,vminitData,vmuninitData,vmuserStack}; 分别代表此页数据为代码,初始化数据,未初始化数据,用户栈。 交换区SWAP 曾在实验7-8中,在progtest.cc文件中声明了BitMap *Mmbmp(如图1),记录mainMemory中物理页的分配情况。它的位置表明了,此Mmbmp的作用域是整个Nachos系统,它不隶属于任何一个用户进程。当然,我们可以实现一个更好的方式:将Mmbmp放到Machine中,但是这要修改Machine的定义, 14
如果查看Machine类定义就可以知道,Machine牵扯到Nachos的核心的系统控制,为了尽量保证Nachos系统的稳定性,则将BitMap *Mmbmp作为全局变量放在了progtest.cc中。
同样的道理,将交换区文件SWAP的生命周期与Mmbmp相似,同时SWAP也需要一个BitMap *SwapBitmap记录SWAP各个页的使用情况,所以,在protest.cc中添加声明:
BitMap *Mmbmp=new BitMap(NumPhysPages); //bitmap for allocating of physical pages infjkdjk mainMemory.
BitMap *SwapBitmap = new BitMap(NumPhysPages); //bitmap for SWAP file, //assume the size of SWAP file is NumPhyPages. OpenFile *SwapFile = fileSystem->Open("SWAP"); //stub in Nachos_Linux //在lab11的目录下建立文件SWAP NoffHeader 修改原有的结构体NoffHeader为类类型,目的是为了能够将NoffHeader作为AddrSpace类的私有实例变量存取,结构体无法实例化为类的私有变量,所以将结构体NoffHeader重写,变为类NoffHeader,并一起更改结构体NoffSegment为类类型。两者的功能在保证原结构体功能的基础上,为了调试和输出方便,添加输出函数Print()。具体定义如下:
#define NOFFMAGIC 0xbadfad class NoffSegment { public: int virtualAddr; int inFileAddr; int size;
void Print(); NoffSegment(); ~NoffSegment(); 14
}; class NoffHeader { public: int noffMagic; NoffSegment code; NoffSegment initData; NoffSegment uninitData;
void Print(); NoffHeader(); ~NoffHeader(); }; AddrSpace 扩展原有的AddrSpace的属性: 添加属性——当下正在执行的用户文件的指针OpenFile *executable,因为我们无法一次读取所有需要的数据,更多情况下,我们边用边读,所以设置一个变量executable来保存指向用户文件的指针。
添加属性——当下正在执行的用户文件的NoffHeader,因为NoffHeader在初始化时,将会加载到mainMemory的0号地址中,一旦程序运行之后,原0号地址中的内容必定会被用户程序重写,但因为我采用的是bitmap做物理地址与虚地址的变换,其中的变换细节要求需要在进行物理和虚拟页变换时知道code的virtualAddr,initData的virtualAddr等的数据,(详细细节见AddrSpace::Translate介绍)所以为了访问方便,设置其为用户进程的一个属性。
添加virtualMem数组和p_vm指针,用来实现FIFO算法。virtualMem存储的是按进入内存的先后顺序排列的当前占用内存空间的虚页,p_vm指针指向数组中当前将要被换出的那个位置。(详细说明见AddrSpace::FIFO介绍)
private: TranslationEntry *pageTable; // Assume linear page table translation for now! 14
unsigned int numPages; // Number of pages in the virtual address space OpenFile *executable; //A pointer to the executing file NoffHeader noffH; // The header of the OpenFile executable int virtualMem[MemPages]; // Store virtual pages of the pages in the main memory int p_vm; //The pointer to next memory to swap out 添加AddrSpace实现用户空间虚拟内存的函数: void InitPageTable(); //用于初始化AddrSpace的pageTable的基本信息 void InitInFileAddr(); //初始化pageTable中各个entry的inFileAddr、type void FIFO(int newPage); //调用translate和swap实现先进先出的虚拟内存置换算法 void Translate(int addr,unsigned int* vpn, unsigned int *offset); //将addr对应的虚拟页页号vpn和页内偏移量offset计算出来 void Swap(int oldPage, int newPage); //调用WriteBack和ReadIn //实现将mainMemory中的oldPage替换成newPage void WriteBack(int oldPage); //将oldPage这一个页写回 //code和initData将会被写回文件; //uninitData和userStack内容将会被写回交换区SWAP void ReadIn(int newPage); //将newPage写入到mainMemory //code和initData将通过inFileAddr从文件中读出; //uninitData和userStack或从交换区SWAP读出,或只是将mainMemory中分配到的地址段清零 关键源代码及注释 首先,简要说明一下现在Nachos系统的虚拟存储功能的能力。为了简便起见,规定系统默认给每个用户进程分配MemPages大小的主存,当用户的进程装入内存,进行数据初始化的时候,按照用户程序在pageTable中的存储顺序从前向后装入MemPages大小的页到内存中去。在用户进程在运行的过程之中,如果访问内存无法找到想要的virtualAddr,那么采用FIFO策略进行不同页之间的切换。