分段、分页以及虚拟地址空间

提一下这本书里使我深受启发的一句话:计算机科学领域的任何问题都可以通过增加一个间接的中间层来解决。

下面摘自:《程序员的自我修养》

  在早期的计算机中,程序是直接运行在物理内存上的,也就是说,程序在运行时所访问的地址都是物理地址。当然,如果一个计算机同时只运行一个程序,那么只要程序要求的内存空间不要超过物理内存的大小,就不会有问题。但事实上为了更有效地利用硬件资源,我们必须同时运行多个程序,正如前面的多道程序、分时系统和多任务中一样,当我们能够同时运行多个程序时,CPU的利用率将会比较高。那么很明显的一个问题是,如何将计算机上有限的物理内存分配给多个程序使用
  假设我们的计算机有128MB内存,程序A运行需要10MB,程序B需要100MB,程序C需要20MB。如果我们需要同时运行程序A和B,那么比较直接的做法是将内存的前10MB分配给程序A,10MB~110MB分配给B。这样就能够实现A和B两个程序同时运行,但是这种简单的内存分配策略问题很多。
地址空间不隔离  所有程序都直接访问物理地址,程序所使用的内存空间不是相互隔离的。恶意的程序可以很容易改写其他程序的内存数据,以达到破坏的目的;有些非恶意的、但是有臭虫的程序可能不小心修改了其他程序的数据,就会使其他程序也崩溃,这对于需要安全稳定的计算环境的用户来说是不能容忍的。用户希望他在使用计算机的时候,其中一个任务失败了,至少不会影响其他任务。
内存使用效率低  由于没有有效的内存管理机制,通常要一个程序执行时,监控程序就将整个程序装入内存中然后开始执行。如果我们忽然要运行程序C,那么这时内存空间其实已经不够了,这时候我们可以用的一个办法是将其他程序的数据暂时写到磁盘里面,等到要用到的时候再读回来。由于程序所需要的空间是连续的,那么这个例子里面,如果我们将程序A换出到磁盘所释放的内存空间是不够的,所以只能将B换出到磁盘,然后将C读入到内存开始运行。可以看到整个过程中有大量的数据在换入换出,导致效率十分低下。
程序运行的地址不确定  因为程序每次需要装入运行时,我们都需要给它从内存中分配一块足够大的空闲区域,这个空闲区域的位置是不确定的。这给程序的编写造成了一定的麻烦,因为程序在编写时,它访问数据和指令跳转时的目标地址很多都是固定的,这涉及程序的重定位问题,我们在第2部分和第3部分还会详细探讨重定位的问题。
  解决这几个问题的思路就是使用我们前文提到过的法宝:增加中间层,即使用一种间接的地址访问方法。整个想法是这样的,我们把程序给出的地址看作是一种虚拟地址(Virtual Address),然后通过某些映射的方法,将这个虚拟地址转换成实际的物理地址。这样,只要我们能够妥善地控制这个虚拟地址到物理地址的映射过程,就可以保证任意一个程序所能够访问的物理内存区域跟另外一个程序相互不重叠,以达到地址空间隔离的效果。

隔离

地址空间分两种:虚拟地址空间和物理地址空间。物理地址空间是实实在在存在的,存在于计算机中,而且对于每一台计算机来说只有唯一的一个,你可以把物理空间想象成物理内存。虚拟地址空间是指虚拟的、人们想象出来的地址空间,其实它并不存在,每个进程都有自己独立的虚拟空间,而且每个进程只能访问自己的地址空间,这样就有效地做到了进程的隔离。

分段

最开始人们使用的是一种叫做分段的方法,基本思路是把一段与程序所需要的内存空间大小的虚拟空间映射到某个物理地址空间。具体是把两块相同大小的地址空间(虚拟地址空间和物理地址空间)一一映射,即虚拟空间中的每个字节对应于物理空间中的每个字节。这个映射过程由软件来设置,比如操作系统来设置这个映射函数,实际的地址转换由硬件完成。

分段解决了地址空间不隔离和程序运行的地址不确定的问题,但是并没有解决内存使用效率的问题。分段对内存区域的映射还是按照程序为单位,如果内存不足,被换入换出到磁盘的都是整个程序,这样势必会造成大量的磁盘访问操作,从而严重影响速度,这种方法还是显得粗糙,粒度比较大。事实上,根据程序的局部性原理,当一个程序在运行时,在某个时间段内,它只是频繁地用到了一小部分数据,也就是说,程序的很多数据其实在一个时间段内都是不会被用到的。人们很自然地想到了更小粒度的内存分割和映射的方法,使得程序的局部性原理得到充分的利用,大大提高了内存的使用率。这种方法就是分页。

分页

分页的基本方法是把地址空间人为的分成固定大小的页,每一页的大小由硬件决定,或硬件支持多种大小的页,由操作系统选择决定页的大小。目前几乎所有pc上的操作系统都是用4KB大小的页。我们使用的PC机是32位的虚拟地址空间,也就是4GB,那么按4KB每页分的话,总共有1048576个页。物理空间也是同样的分法。

当我们把进程的虚拟地址空间按页分割,把常用的数据和代码页装载到内存中,把不常用的代码和数据保存在磁盘里,当需要使用的时候再把它从磁盘里取出来即可。在这里我们把虚拟空间的页就叫做虚拟页,把物理内存中的页叫做物理页,把磁盘中的页叫做磁盘页。当不同虚拟空间的页被映射到同一个物理页,这样就可以实现内存共享。

当进程需要用到虚拟页映射的磁盘页时,因为磁盘页并不在内存中,硬件会捕获到这个消息,就是所谓的页错误,然后操作系统接管进程负责将磁盘页从磁盘中读出来并装入内存,然后再将内存中该物理页与虚拟页重新建立映射关系。以页为单位来存取和交换这些数据非常方便,硬件本身就支持这种以页为单位的操作方式。

保护也是页映射的目的之一,简单地说就是每个页可以设置权限属性,谁可以修改,谁可以访问等,而只有操作系统有权限修改这些属性,那么操作系统就可以做到保护自己和保护进程。

虚拟存储的实现需要依靠硬件的支持,对于不同的CPU来说是不同的。但是几乎所有的硬件都采用一个叫MMU(Memory Management Unit)的部件来进行页映射。如下图所示,

在页映射模式下,CPU发出的是虚拟地址,即我们的程序看到的是虚拟地址。经过MMU转换之后就变成了物理地址。一般MMU都集成在CPU内部了,不会以单独的部件存在。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值