背景
第八章所介绍的内存管理算法都是基于一个基本要求:执行指令必须在物理内存中,满足这一要求的第一种方法是整个进程放在内存中。动态载入能帮助减轻这一限制,但是它需要程序员特别小心地做一些额外的工作。
指令必须都在物理内存内的这一限制,似乎是必须和合理的,但也是不幸的,因为这使得程序的大小被限制在物理内存的大小内。事实上,研究实际程序会发现,许多情况下并不需要将整个程序放到内存中。即使在需要完整程序的时候,也并不是同时需要所有的程序。
因此运行一个部分在内存中的程序不仅有利于系统,还有利于用户。
虚拟内存(virtual memory)将用户逻辑内存和物理内存分开。这在现有物理内存有限的情况下,为程序员提供了巨大的虚拟内存。
进程的虚拟地址空间就是进程如何在内存中存放的逻辑(或虚拟)视图。通常,该视图为进程从某一个逻辑地址(如地址0)开始,连续存放。
根据第八章,物理地址可以按页幁来组织,且分配给进程的物理页帧也可能不是连续的。这就需要
内存管理单元(MMU)将逻辑页映射到内存的物理页帧。
如上图显示,运行随着动态内存的分配,堆可向上生长。类似地,还允许随着子程序的不断调用,栈可以向下生长。堆与栈之间的巨大空白空间(或hole)为虚拟地址的一部分,只有在堆与栈生长的时候,才需要实际的物理页。
包括空白的虚拟地址空间成为稀地址空间,采用稀地址空间的优点是:随着程序的执行,栈或者堆段的生长或需要载入动态链接库(或共享对象)时,这些空白可以填充。
除了将逻辑内存与物理内存分开,虚拟内存也允许文件和内存通过共享页而为两个或者多个进程所共享,这样带来了如下的有点:
- 通过将共享对象映射到虚拟地址空间,系统库可为多个进程所共享。虽然每个进程都认为共享库是其虚拟地址空间的一部分,而共享库所用的物理内存的实际页是为所有进程所共享。通常,库是按制度方式来链接每个进程的空间的。
- 类似的,虚拟内存允许进程共享内存。两个或者多个进程之间可以通过使用共享内存来相互通信。虚拟内存允许一个进程创建内存区域,以便与其他进程进行共享。共享该内存区域的进程认为它是其虚拟地址空间的一部分,而事实上这部分是共享的。
- 虚拟内存可允许在用系统调用fork()创建进程期间共享页,从而加快进程的创建。