要说虚拟内存(简称VM)就必须要先分别解释一下‘虚拟’和‘内存’。之前讲过,内存可以理解为一种非持续性的储存装置,内存中的数据不会再电源中断后被保存下来,一般人提到内存大多数指的是计算机的主存(main memory),在虚拟内存里也不例外。所谓虚拟即非真实,但虚拟出来的东西大抵是来补充或加强真实中不足,最近开始流行的VR(虚拟现实)就是个最好的例子。跟计算机相关的,你一定也听说过虚拟机和加密电子货币,它们都是对现存的物理机和通用货币的一种加强。虚拟内存也不例外,它是对物理内存的局限性的一种扩展。
那么为什么要加入VM这个概念呢?最早期的原因估计是物理内存太小,而且贵,但又不能说因此就不开发需要较大内存的程序了,于是乎,有人提议用万能的indirection来解决一下吧。试想内存虽然不够大,但是硬盘够大,还便宜,而且在同一时间CPU不会想去使用所有的内存,如果这时候一个程序想要更多的内存但是当前内存都满了,那么闲置中的程序的内存可以先暂时‘撤退’到硬盘里,腾出空间给更需要的程序,等到不再闲置的时候在交换回来,并且继续运行。这个概念听起来没什么问题,但是系统怎么知道刚才‘撤退’的内存应该回到什么位置呢?好办,弄个table把它们对应起来,一边是物理内存的地址,另一边是硬盘上的位置,也可以称为是虚拟内存的地址。
VM概念的核心就是通过这样一个indirection把物理内存和虚拟出来的内存空间对应起来,也可以理解为是虚拟地址和物理地址间转换的管理,这个indirection有个名字叫Page Table。
有了Page Table之后,不光空间问题解决了,还顺带加入了一些更神奇的功能。内存虽然可以被认为是一个线性的array,但是可用的空间并不是连续的,俗称有个”hole"。另一个更严重的问题就是所有程序都在使用同一个物理地址空间,很容易就会使用到不该使用的地址,甚至无法察觉这一问题的出现。程序员不可能也不应该时时刻刻惦记着这些问题来开发,这时候VM就又来拯救世界了。有了VM后,程序中的地址不再是物理地址(Physical Address),而是虚拟地址(Virtual Address),虚拟地址没有物理上的界限也没有那个"hole",每个程序都有自己的单独的虚拟地址空间,它可以尽可能方便自己来使用地址空间,只要Page Table中有对应的物理地址,那么这个虚拟地址就是合理的,一段连续的虚拟地址对应的究竟是连续的物理地址,还是断断续续的,程序开发者甚至不需要知道也不在意这个真相。
等等,如果说每个程序都有自己的虚拟地址空间,而且其相对应的物理地址永远不会冲突的话,那如果两个程序想要使用同一个地址上的数据怎么办呢?没有VM之前这似乎很简单,因为地址是绝对的,加入了Page Table似乎让这变得不可能了。这确实是个问题,而且VM并没有抹除这种可能性,Page Table里除了PA和VA的数字对应,还有额外的信息来标明地址的访问权限。如果想要share一个地址上的数据,则可以通过标记这个地址为‘共享’并在Page Table中加入多对一的关系即可。