第九章 虚拟内存

第九章-----虚拟内存
       系统中的进程共享CPU和主存资源,但存储器空间是有限的,而且还容易被破坏。现代系统提供了一种对主存的抽象,称为虚拟存储器,以更有效地管理存储器。虚拟存储器将主存看作磁盘上的地址空间的高速缓存,为每个进程提供了一致的地址空间,并保护进程的地址空间不被其他进程破坏。
       为了更有效地管理内存并且少出错,现代系统提供了一种对主存的抽象概念,叫做虚拟内存(VM)。虚拟内存是硬件异常、硬件地址翻译、主存、磁盘文件和内核软件的俺没交互,它为每个进程提供了一个大的、一致的和私有的地址空间。通过一个很清晰的机制,虚拟地址内存提供了三个重要的能力: 
        ● 它将主存看成是一个存储在磁盘上的地址空间的高速缓存,在主存中只保存活动区域,并根据需要在磁盘和主存之间来回传送数据,通过这种方式,它高效地使用了主存。
       ● 它为每个进程提供了一致的地址空间,从而简化了内存管理。
       ● 它保护了每个进程的地址空间不被其他进程破坏。
1.物理和虚拟地址
       计算机系统的主存被组织成一个由M个连续的字节大小的单元组成的数组。每字节都有一个唯一地物理地址(Physical Address, PA)。第一个字节的地址为0,接下来的字节地址为1,再下一个为2,以此类推。给这种简单的结构,CPU访问内存的最自然的方式就是使用物理地址。我们把这种方式称为物理寻址。
       早期的PC使用物理地址,而且诸如数字信号处理器、嵌入式微控制器以及Cray超级计算机这样的系统仍然继续使用这种寻址方式。然而现代处理器使用的是一种称为 虚拟寻址的寻址形式。如下图:
       
       使用虚拟寻址,CPU通过生成一个虚拟地址(Virtual Address, VA)来访问主存,这个虚拟地址在被送到内存之前先转换成适当的物理地址。将一个虚拟地址转换为物理地址的任务叫做 地址翻译。就像异常处理一样,地址翻译需要CPU硬件和操作系统之间的紧密合作。CPU芯片上叫做内存管理单元(Memory Management Unit, MMU)的专用硬件,利用存放在主存中的查询表来动态翻译虚拟地址,该表的内容由操作系统管理。
2.虚拟内存作为缓存的工具
      概念上而言,虚拟内存被组织为一个由存放在磁盘上的N个连续的字节大小的单元组成的数组。每字节都有一个唯一地虚拟地址,作为到数组的索引。磁盘上数组的内容被缓存在主存中。和存储器层次结构中其它缓存一样,磁盘(较低层)上的数据被分割成块,这些块作为磁盘和主存(较高层)之间的传输单元。VM系统通过将虚拟内存分割为称为虚拟页(Virtual Page, VP)的大小固定的块来处理这个问题。每个虚拟页的大小为 字节。类似地,物理内存被分割为物理页(Physical Page,PP),大小也为P字节(物理页也被称为页帧)。
      一个地址空间的大小由表示最大地址所需要的位数来描述的。例如,一个包含N= 个地址虚拟地址空间就叫做一个n位地址空间。现代系统通常支持32位或者64位虚拟地址空间。
      在任意时刻,虚拟页面的集合都分为三个不想交的子集:
       ● 未分配的:VM系统还未分配(或者创建)的页。未分配的块没有任何数据和它们相关联,因此也就不占用任何磁盘空间。
      ● 缓存的:当前已缓存在物理内存中的已分配页。
      ● 未缓存的: 未缓存在物理内存中的已分配页。
3.DRAM缓存的组织结构
      在存储层次结构中,DRAM缓存的位置对它的组织结构有很大的影响。回想一下,DRAM比SRAM要慢大约10倍,而磁盘要比DRAM慢大约100 000多倍。一次DRAM缓存中的不命中比起SRAM缓存中的不命中要昂贵的多,这是因为DRAM缓存不命中要由磁盘来服务,而SRAM缓存不命中通常是由基于DRAM的主存来服务的。而且,从磁盘的第一个扇区读取第一个字节的时间开销比起读这个扇区中连续的字节慢大约100 000倍。
      因为大的不命中处罚和访问第一个字节的开销,虚拟页往往很大,通常是4KB~2MB。
4.页表
      同任何缓存一样,虚拟内存系统必须有某种方法来判定一个虚拟页是否缓存在DRAM中的某个地方。如果是,系统还必须确定这个虚拟页存放在哪个物理页。如果不命中,系统必须判断这个虚拟页存放在磁盘的哪个位置,在物理内存中选择一个牺牲页,并将虚拟页从磁盘复制到DRAM中,替换这个牺牲页。
      这些功能是由软硬件联合提供的,包括操作系统软件、MMU(内存管理单元)中的地址翻译硬件和一个存放在物理内存中叫做页表的数据结构,页表将虚拟页映射到物理页。每次地址翻译硬件将一个虚拟地址转换为物理地址时,都会读取页表。操作系统负责维护页表内容,以及在磁盘与DRAM之间来回传送页。
      下图展示了一个页表的基本组织结构。页表就是一个页表条目(Page Table Entry, PTE)的数组。虚拟地址空间中的每个页中一个固定偏移量处都有一个PTE。假设每个PTE都由一个有效位和一个n位地址字段组成的。有效位表明了该虚拟页当前是否被缓存在DRAM中。如果设置了有效位,那么地址字段就表示DRAM中相应的物理页的起始地址。如果没有设置有效位,那么一个空地址表示这个虚拟页还未分配。否则,这个地址就指向该虚拟页在磁盘上的起始位置。
      
     上图展示了一个有8个虚拟页和4个物理页的系统的页表。四个虚拟页(VP1、VP2、VP4和VP7)当前被缓存在DRAM中。两个页(VP0和VP5)还未被分配,而剩下的页(VP3和VP6)已经被分配了,但是当前还未被缓存。
      ● 页命中
      考虑一下当CPU想要读包含在VP2中的虚拟内存的一个字时会发生什么,VP2被缓存在DRAM中。使用地址翻译技术,地址翻译硬件将虚拟地址作为一个索引来定位PTE2,并从内存中读取它。因为设置了有效位,那么地址翻译硬件就知道VP2是缓存在内存中的了。所以它使用PTE中的物理内存地址(该地址指向PP1中缓存页的起始位置),构造出这个字的物理地址。
       
       ● 缺页
       在虚拟内存的习惯说法中,缓存不命中称为缺页。下图展示了在缺页之前我们的示例页表的状态。CPU引用了VP3中的一个字,VP3并未缓存在DRAM中。地址翻译硬件从内存中读取PTE3,从有效位推断出VP3未被缓存,并且触发一个缺页异常。缺页异常调用内核中的缺页异常处理程序,该程序会选择一个牺牲页,在此例中就是存放在PP3中的VP4。如果VP4已经被修改了,那么内核就会将它复制回磁盘。无论哪种情况,内核都会修改VP4的页表条目,反映出VP4不再还存在主存中这一事实。
       
       接下来,内核从磁盘复制VP3到内存中的PP3,更新PTE3,随后返回。当异常处理程序返回时,它会重新启动导致缺页的指令,该指令会把导致缺页的虚拟地址重发送到地址翻译硬件。但是现在,VP3已经缓存在主存中了,那么页命中也能由地址翻译硬件正常处理了。下图展示了在缺页之后我们的示例页表的状态。
       
5.地址翻译
        形式上来说,地址翻译是一个N元素的虚拟地址空间(VAS)的元素和一个M元素的物理地址空间(PAS)中元素之间的映射,
                                                            
       这里
              
      下图展示了MMU如何利用页表来实现这种映射。CPU中的一个控制寄存器,页表基址寄存器(Page Table Base Register, PTRB)指向当前页表。n位的虚拟地址包含两个部分:一个p位的虚拟页面偏移(Virtual Page Offset, VPO)和一个(n-p)位的虚拟页号(Virtual Page Number, VPN)。MMU利用VPN来选择适当的PTE。例如,VPN 0选择PTE 0,VPN 1选择PTE 1,以此类推。将页表条目中物理页号(Physical Page Number,PPN)和虚拟地址中的VPO串联起来,就得到相应的物理地址。
       
           ● 多级页表 
         用来压缩页表的常用方法是使用层次结构的页表。用一个具体的示例是最容易理解这个思想的。假设32位虚拟地址空间被分配位4KB的页,而每个页表条目都是4字节。还假设在这一时刻,虚拟地址空间有如下形式:内存的前2K个页面分配给了代码和数据,接下来6K个页面未分配,再接下来的1023个也未分配,接下来的1个页面分配给了用户栈。下图展示了如何为虚拟空间构造一个两级也表层次结构:
        
6.Linux虚拟内存区域
        下图记录了一个进程中虚拟内存区域的内核数据结构。内核为系统中的每个进程维护一个单独的任务结构(源代码中的task_struct)。任务结构中的元素包含或者指向内核运行该进程所需要的所有信息(例如,PID、指向用户栈的指针、可执行目标文件的名字,以及程序计数器)。
       
      任务结构中的一个条目指向mm_struct,它描述了虚拟内存的当前状态。我们感兴趣的两个字段是pgd和mmap,其中pgd指向第一级页表(页全局目录)的基址,而mmap指向一个vm_area_structs(区域结构)的链表,其中每个vm_area_structs都描述了当前虚拟地址空间的区域。当内核运行这个进程时,就将pgd存放在CR3控制寄存器中。
      一个具体区域结构包含下面的字段:
      ●   vm_start: 指向这个区域的起始处。
      ●  vm_end: 指向这个区域的结束处。
     ●  vm_prot: 描述这个区域内包含的所有页的读写许可权限。
     ●  vm_flags:描述这个区域内的页面是与其他进程共享的,还是这个进程私有的(还描述了其他一些信息)。
     ●  vm_next: 指向链表中的下一个区域结构。
7.内存映射
     Linux通过将虚拟内存区域与磁盘上的对象关联起来,以初始化这个虚拟内存区域的内容,这个过程称为内存映射

猜你喜欢

转载自blog.csdn.net/weixin_41413441/article/details/79493126
今日推荐