虚拟内存、物理内存与页

2020/02/14 Knowledge

内存是程序得以运行的重要物质基础。如何在有限的内存空间运行较大的应用程序,曾是困扰人们的一个难题。为解决这个问题,人们设计了许多的方案,其中最成功的当属虚拟内存技术。Linux作为一个以通用为目的的现代大型操作系统,当然也毫不例外的采用了优点甚多的虚拟内存技术。参考博客Linux的虚拟内存详解

虚拟内存的概念

总所周知,为了对内存中的存储单元进行识别,内存中的每一个存储单元都必须有一个确切的地址。而一台计算机的处理器能访问多大的内存空间就取决于处理器的程序计数器,该计数器的字长越长,能访问的空间就越大

例如:对于程序计数器位数为32位的处理器来说,他的地址发生器所能发出的地址数目为2^32=4G个,于是这个处理器所能访问的最大内存空间就是4G。在计算机技术中,这个值就叫做处理器的寻址空间或寻址能力。

照理说,为了充分利用处理器的寻址空间,就应按照处理器的最大寻址来为其分配系统的内存。如果处理器具有32位程序计数器,那么就应该按照下图的方式,为其配备4G的内存:

1

这样,处理器所发出的每一个地址都会有一个真实的物理存储单元与之对应;同时,每一个物理存储单元都有唯一的地址与之对应。这显然是一种最理想的情况。

但遗憾的是,实际上计算机所配置内存的实际空间常常小于处理器的寻址范围,这是就会因处理器的一部分寻址空间没有对应的物理存储单元,从而导致处理器寻址能力的浪费。例如:如下图的系统中,具有32位寻址能力的处理器只配置了256M的内存储器,这就会造成大量的浪费:

2

另外,还有一些处理器因外部地址线的根数小于处理器程序计数器的位数,而使地址总线的根数不满足处理器的寻址范围,从而处理器的其余寻址能力也就被浪费了。例如:Intel8086处理器的程序计数器位32位,而处理器芯片的外部地址总线只有20根,所以它所能配置的最大内存为1MB:

3

在实际的应用中,如果需要运行的应用程序比较小,所需内存容量小于计算机实际所配置的内存空间,自然不会出什么问题。但是,目前很多的应用程序都比较大,计算机实际所配置的内存空间无法满足。

实践和研究都证明:一个应用程序总是逐段被运行的,而且在一段时间内会稳定运行在某一段程序里

这也就出现了一个方法:如下图所示,把要运行的那一段程序自辅存复制到内存中来运行,而其他暂时不运行的程序段就让它仍然留在辅存

4

当需要执行另一端尚未在内存的程序段(如程序段2),如下图所示,就可以把内存中程序段1的副本复制回辅存,在内存腾出必要的空间后,再把辅存中的程序段2复制到内存空间来执行即可:

5

在计算机技术中,把内存中的程序段复制回辅存的做法叫做“换出”,而把辅存中程序段映射到内存的做法叫做“换入”。经过不断有目的的换入和换出,处理器就可以运行一个大于实际物理内存的应用程序了。或者说,处理器似乎是拥有了一个大于实际物理内存的内存空间。于是,这个存储空间叫做虚拟内存空间,而把真正的内存叫做实际物理内存,或简称为物理内存

那么对于一台真实的计算机来说,它的虚拟内存空间又有多大呢?计算机虚拟内存空间的大小是由程序计数器的寻址能力来决定的。例如:在程序计数器的位数为32的处理器中,它的虚拟内存空间就为4GB。

可见,如果一个系统采用了虚拟内存技术,那么它就存在着两个内存空间:虚拟内存空间和物理内存空间虚拟内存空间中的地址叫做“虚拟地址”;而实际物理内存空间中的地址叫做“实际物理地址”或“物理地址”处理器运算器和应用程序设计人员看到的只是虚拟内存空间和虚拟地址,而处理器片外的地址总线看到的只是物理地址空间和物理地址

由于存在两个内存地址,因此一个应用程序从编写到被执行,需要进行两次映射。第一次是映射到虚拟内存空间,第二次时映射到物理内存空间在计算机系统中,第两次映射的工作是由硬件和软件共同来完成的承担这个任务的硬件部分叫做存储管理单元MMU,软件部分就是操作系统的内存管理模块了

在映射工作中,为了记录程序段占用物理内存的情况,操作系统的内存管理模块需要建立一个表格,该表格以虚拟地址为索引,记录了程序段所占用的物理内存的物理地址。这个虚拟地址/物理地址记录表便是存储管理单元MMU把虚拟地址转化为实际物理地址的依据,记录表与存储管理单元MMU的作用如下图所示:

6

综上所述,虚拟内存技术的实现,是建立在应用程序可以分成段,并且具有“在任何时候正在使用的信息总是所有存储信息的一小部分”的局部特性基础上的。它是通过用辅存空间模拟RAM来实现的一种使机器的作业地址空间大于实际内存的技术。

从处理器运算装置和程序设计人员的角度来看,它面对的是一个用MMU、映射记录表和物理内存封装起来的一个虚拟内存空间,这个存储空间的大小取决于处理器程序计数器的寻址空间

可见,程序映射表是实现虚拟内存的技术关键,它可给系统带来如下特点:

  • 系统中每一个程序各自都有一个大小与处理器寻址空间相等的虚拟内存空间;
  • 在一个具体时刻,处理器只能使用其中一个程序的映射记录表,因此它只看到多个程序虚存空间中的一个,这样就保证了各个程序的虚存空间时互不相扰、各自独立的;
  • 使用程序映射表可方便地实现物理内存的共享。

Linux的虚拟内存技术

以存储单元为单位来管理显然不现实,因此Linux把虚存空间分成若干个大小相等的存储分区,Linux把这样的分区叫做页。为了换入、换出的方便,物理内存也就按也得大小分成若干个块。由于物理内存中的块空间是用来容纳虚存页的容器,所以物理内存中的块叫做页框。页与页框是Linux实现虚拟内存技术的基础。

虚拟内存的页、物理内存的页框及页表

在Linux中,页与页框的大小一般为4KB。当然,根据系统和应用的不同,页与页框的大小也可有所变化。

物理内存和虚拟内存被分成了页框与页之后,其存储单元原来的地址都被自然地分成了两段,并且这两段各自代表着不同的意义:高位段分别叫做页框码和页码,它们是识别页框和页的编码;低位段分别叫做页框偏移量和页内偏移量,它们是存储单元在页框和页内的地址编码。下图就是两段虚拟内存和物理内存分页之后的情况:

7

为了使系统可以正确的访问虚存页在对应页框中的映像,在把一个页映射到某个页框上的同时,就必须把页码和存放该页映像的页框码填入一个叫做页表的表项中。这个页表就是之前提到的映射记录表。一个页表的示意图如下所示:

8

页模式下,虚拟地址、物理地址转换关系的示意图如下所示:

9

也就是说:处理器遇到的地址都是虚拟地址。虚拟地址和物理地址都分成页码(页框码)和偏移值两部分。在由虚拟地址转化成物理地址的过程中,偏移值不变。而页码和页框码之间的映射就在一个映射记录表——页表中

请页与交换

虚存页面到物理页框的映射叫做页面的加载。

当处理器试图访问一个虚存页面时,首先到页表中去查询该页是否已映射到物理页框中,并记录在页表中。如果在,则MMU会把页码转换成页框码,并加上虚拟地址提供的页内偏移量形成物理地址后去访问物理内存;如果不在,则意味着该虚存页面还没有被载入内存,这时MMU就会通知操作系统:发生了一个页面访问错误(页面错误),接下来系统会启动所谓的“请页”机制,即调用相应的系统操作函数,判断该虚拟地址是否为有效地址。

如果是有效的地址,就从虚拟内存中将该地址指向的页面读入到内存中的一个空闲页框中,并在页表中添加上相对应的表项,最后处理器将从发生页面错误的地方重新开始运行;如果是无效的地址,则表明进程在试图访问一个不存在的虚拟地址,此时操作系统将终止此次访问。

当然,也存在这样的情况:在请页成功之后,内存中已没有空闲物理页框了。这是,系统必须启动所谓地“交换”机制,即调用相应的内核操作函数,在物理页框中寻找一个当前不再使用或者近期可能不会用到的页面所占据的页框。找到后,就把其中的页移出,以装载新的页面。对移出页面根据两种情况来处理:如果该页未被修改过,则删除它;如果该页曾经被修改过,则系统必须将该页写回辅存。

系统请页的处理过程如下所示:

10

为了公平地选择将要从系统中抛弃的页面,Linux系统使用最近最少使用(LRU)页面的衰老算法这种策略根据系统中每个页面被访问的频率,为物理页框中的页面设置了一个叫做年龄的属性页面被访问的次数越多,则页面的年龄最小;相反,则越大而年龄较大的页面就是待换出页面的最佳候选者

Search

    Table of Contents