【Nachos】山东大学操作系统实验七 虚拟内存

完整源码见本人博客下载资源

文章目录

      • 一、完成情况一览
      • 二、虚拟内存管理设计
        • 1、缺页异常
        • 2、交换空间
        • 3、缺页异常处理
        • 4、硬件条件
      • 三、实现过程
      • 四、结果展示

一、完成情况一览

  • 了解了Nachos虚拟内存机制,包括翻译物理地址,缺页异常
  • 实现了页换入换出,基础的虚拟内存管理,包括解决缺页异常,帧分配,页置换等

二、虚拟内存管理设计

1、缺页异常

如果要访问的数据不在主存中,会引发缺页异常,然后处理异常,如果没有内存空间就选择一个页换出,将缺的这个页换入。这种机制,使得虚拟内存发挥了更大作用,我们可以在物理内存上运行需要更多虚拟内存的程序。

虚实地址转换的流程图,这其中可能引发缺页异常:

【Nachos】山东大学操作系统实验七 虚拟内存_第1张图片

2、交换空间

换入换出需要交换空间,这里简单的将运行用户程序时传入的文件名作为AddrSpace的成员变量,将该文件作为交换空间。

3、缺页异常处理

需要主要考虑的是采用什么样的帧分配算法和页面置换算法。

这里采用固定分配+局部置换。

固定分配:不是完全固定,而是max(5,必需页数量+1),意味着,如果用户进程很大,它能分到的帧也会很多,必需页的数量由code和initData的总和决定

局部置换:只在本进程空间内寻找牺牲页。按照noff格式的定义,必需页是在虚拟空间的低地址,从零开始。考虑置换时,我们将保证这一部分页始终在内存中,而只选取其他页置换。暂时是随机置换算法,有机会可以实现二次机会算法。

4、硬件条件

nachos的页表项(TranslationEntry对象)已经具备了所需硬件条件。

有valid,dirty,use位。

三、实现过程

有了实验六系统调用的编写经历,处理缺页异常的过程很简单,主要工作在AddrSpace类的功能添加上。

  • AddrSpace类增加

    pulic:
    	int findReplacedPage();
    	void replacePage(int badVAddr);  	
    	void writeback(int oldPage);	
      private:
        TranslationEntry *pageTable;	// Assume linear page table translation
    					// for now!
        int spaceID;
        unsigned int numPages;		// Number of pages in the virtual 
       char *filename;
    	//OpenFile *executable;   //整个虚拟内存空间
        int necessaryFrames;  //初始时,固定分配的最大帧数
    					// address space
    };
    
  • 初始化用户空间AddrSpace(char *filename)更改

主要初始化 necessaryFrames变量,完成帧固定分配任务。


//******************************************
    necessaryFrames=divRoundUp(noffH.code.size + noffH.initData.size,PageSize);	
    int numFrames =max(MaxNumPhysPages,necessaryFrames+1); 
   
    ASSERT(numFrames <= NumPhysPages && numFrames <= freeMM_map->NumClear());		// check we're not trying
						// to run anything too big --
						// at least until we have
						// virtual memory

    DEBUG('a', "Initializing address space, num pages %d, size %d\n", 
					numPages, size);
// first, set up the translation 
    pageTable = new TranslationEntry[numPages];
	for (i=0;iFind();
			pageTable[i].valid = true;
			pageTable[i].use = false;
			pageTable[i].dirty = false;
			pageTable[i].readOnly = false; 
		
	}
	for(i;i
  • 处理页错误中的置换函数部分

    int
    AddrSpace::findReplacedPage()
    {
    	printf("寻找oldPage换出!\n");
    	for (int i=necessaryFrames;i< numPages;i++){
    		if(pageTable[i].valid)
    			return i;
    	}
    }
    	 
    void 
    AddrSpace::replacePage(int badVAddr)
    {
    	int newPage=badVAddr/PageSize;
    	int oldPage=findReplacedPage();
    	printf("页置换!%d换出,%d换入\n",oldPage,newPage);
    	writeback(oldPage);
    	pageTable[oldPage].valid=false;
    	pageTable[newPage].physicalPage=pageTable[oldPage].physicalPage;
    	pageTable[newPage].valid=true;
    	pageTable[newPage].dirty = false;
    	pageTable[newPage].readOnly = false;
    	
    	//read to MM     
    	    OpenFile *executable = fileSystem->Open(filename);
    
    	    if (executable == NULL) {
    		printf("Unable to open file %s\n", filename);
    		return;
    	    }
    	    executable->ReadAt(&(machine->mainMemory[pageTable[newPage].physicalPage]),PageSize, newPage*PageSize);
    	    delete executable;
    	
         Print();
    	
    }
    	
    void 
    AddrSpace::writeback(int oldPage)
    {
    	if(pageTable[oldPage].dirty){
    		printf("dirty!写回磁盘,spaceId:%d,oldPage:%d\n",spaceID,oldPage);
    		OpenFile *executable = fileSystem->Open(filename);
    
    		    if (executable == NULL) {
    			printf("Unable to open file %s\n", filename);
    			return;
    		    }
    		executable->WriteAt(&(machine->mainMemory[pageTable[oldPage].physicalPage]),PageSize,oldPage*PageSize);
    		delete executable;
    	}
    }
    
  • 页错误异常处理,和增加系统调用流程一样,因为都是中断

    void
    ExceptionHandler(ExceptionType which)
    {
        int type = machine->ReadRegister(2);
    
        if (which == SyscallException) {
    	switch(type){	
    	    case SC_Halt:
    		DEBUG('a', "Shutdown, initiated by user program.\n");
       		interrupt->Halt();
    		return;
    	    case SC_Exec:
    
    		interrupt->Exec();
    		AdvancePC();
    		return;
    	
    	}
        } else if(which == PageFaultException){
    		//缺页异常在这处理
    		interrupt->PageFault();
    	}
    	else{
    	printf("Unexpected user mode exception %d %d\n", which, type);
    	ASSERT(FALSE);
        }
    }
    

    在Interrupt类中增加Interrupt::PageFault()成员函数

    这里需注意,造成页错误的虚存地址在$BadVAddrReg寄存器中

    void
    Interrupt::PageFault()
    {// The failing virtual address on an exception
    	int badVAddr= machine->ReadRegister(BadVAddrReg);
    	AddrSpace *space=currentThread->space;
    	space->replacePage(badVAddr);
    }
    
  • 为展示页置换效果,AddrSpace::Print()函数修改

    void
    AddrSpace::Print() 
    { 
    	printf("spaceID: %d\n",spaceID);
    	printf("page table dump: %d pages in total\n", numPages); 
    	printf("============================================\n"); 
    	printf("  VirtPage, PhysPage, valid, dirty,  use\n"); 
    	for (int i=0; i < numPages; i++) { 
    	printf("\t%d,\t%d,\t%d,\t%d,\t%d\n", pageTable[i].virtualPage,pageTable[i].physicalPage,pageTable[i].valid,pageTable[i].dirty,pageTable[i].use); 
    	} 
    	printf("============================================\n\n"); 
    }
    
  • 细节:AddrSpace::AddrSpace()构造函数参数修改为文件名,所以,对应地,StartProgress以及Exec系统调用都要做小小的更改

四、结果展示

下面的图片请连成一幅图看

【Nachos】山东大学操作系统实验七 虚拟内存_第2张图片【Nachos】山东大学操作系统实验七 虚拟内存_第3张图片【Nachos】山东大学操作系统实验七 虚拟内存_第4张图片【Nachos】山东大学操作系统实验七 虚拟内存_第5张图片

你可能感兴趣的:(操作系统)