对进程空间的认识

(为何32位的机器的进程地址空间为4GB)html

在进入正题前先来谈谈操做系统内存管理机制的发展历程,了解这些有利于咱们更好的理解目前操做系统的内存管理机制。windows

1、早期的内存分配机制数据结构

在 早期的计算机中,要运行一个程序,会把这些程序全都装入内存,程序都是直接运行在内存上的,也就是说程序中访问的内存地址都是实际的物理内存地址。当计算机同时运行多个程序时,必须保证这些程序用到的内存总量要小于计算机实际物理内存的大小。那当程序同时运行多个程序时,操做系统是如何为这些程序分配内存 的呢?下面经过实例来讲明当时的内存分配方法:函数

某台计算机总的内存大小是 128M ,如今同时运行两个程序 A 和 B , A 需占用内存 10M , B 需占用内存 110 。计算机在给程序分配内存时会采起这样的方法:先将内存中的前 10M 分配给程序 A ,接着再从内存中剩余的 118M 中划分出 110M 分配给程序 B 。这种分配方法能够保证程序 A 和程序 B 都能运行,可是这种简单的内存分配策略问题不少。spa

 

图一 早期的内存分配方法操作系统

问题 1 :进程地址空间不隔离。因为程序都是直接访问物理内存,因此恶意程序能够随意修改别的进程的内存数据,以达到破坏的目的。有些非恶意的,可是有 bug 的程序也可能不当心修改了其它程序的内存数据,就会致使其它程序的运行出现异常。这种状况对用户来讲是没法容忍的,由于用户但愿使用计算机的时候,其中一个任务失败了,至少不能影响其它的任务。线程

问题 2 :内存使用效率低。在 A 和 B 都运行的状况下,若是用户又运行了程序 C ,而程序 C 须要 20M 大小的内存才能运行,而此时系统只剩下 8M 的空间可供使用,因此此时系统必须在已运行的程序中选择一个将该程序的数据暂时拷贝到硬盘上,释放出部分空间来供程序 C 使用,而后再将程序 C 的数据所有装入内存中运行。能够想象获得,在这个过程当中,有大量的数据在装入装出,致使效率十分低下。指针

问题 3 :程序运行的地址不肯定。当内存中的剩余空间能够知足程序 C 的要求后,操做系统会在剩余空间中随机分配一段连续的 20M 大小的空间给程序 C 使用,由于是随机分配的,因此程序运行的地址是不肯定的。htm

2、分段对象

为 了解决上述问题,人们想到了一种变通的方法,就是增长一个中间层,利用一种间接的地址访问方法访问物理内存。按照这种方法,程序中访问的内存地址再也不是实际的物理内存地址,而是一个虚拟地址,而后由操做系统将这个虚拟地址映射到适当的物理内存地址上。这样,只要操做系统处理好虚拟地址到物理内存地址的映 射,就能够保证不一样的程序最终访问的内存地址位于不一样的区域,彼此没有重叠,就能够达到内存地址空间隔离的效果。

当建立一个进程时,操做系统会为该进程分配一个 4GB 大小的虚拟 进程地址空间。之因此是 4GB ,是由于在 32 位的操做系统中,一个指针长度是 4 字节,而 4 字节指针的寻址能力是从 0x00000000~0xFFFFFFFF ,最大值 0xFFFFFFFF 表示的即为 4GB 大小的容量。与虚拟地址空间相对的,还有一个物理地址空间,这个地址空间对应的是真实的物理内存。若是你的计算机上安装了 512M 大小的内存,那么这个物理地址空间表示的范围是 0x00000000~0x1FFFFFFF 。当操做系统作虚拟地址到物理地址映射时,只能映射到这一范围,操做系统也只会映射到这一范围。当进程建立时,每一个进程都会有一个本身的 4GB 虚拟地址空间。要注意的是这个 4GB 的地址空间是“虚拟”的,并非真实存在的,并且每一个进程只能访问本身虚拟地址空间中的数据,没法访问别的进程中的数据,经过这种方法实现了进程间的地址隔离。那是否是这 4GB 的虚拟地址空间应用程序能够随意使用呢?很遗憾,在 Windows 系统下,这个虚拟地址空间被分红了 4 部分: NULL 指针区、用户区、 64KB 禁入区、内核区。应用程序能使用的只是用户区而已,大约 2GB 左右 ( 最大能够调整到 3GB) 。内核区为 2GB ,内核区保存的是系统线程调度、内存管理、设备驱动等数据,这部分数据供全部的进程共享,但应用程序是不能直接访问的。

      人 们之因此要建立一个虚拟地址空间,目的是为了解决进程地址空间隔离的问题。但程序要想执行,必须运行在真实的内存上,因此,必须在虚拟地址与物理地址间创建一种映射关系。这样,经过映射机制,当程序访问虚拟地址空间上的某个地址值时,就至关于访问了物理地址空间中的另外一个值。人们想到了一种分段 (Sagmentation) 的方法,它的思想是在虚拟地址空间和物理地址空间之间作一一映射。好比说虚拟地址空间中某个 10M 大小的空间映射到物理地址空间中某个 10M 大小的空间。这种思想理解起来并不难,操做系统保证不一样进程的地址空间被映射到物理地址空间中不一样的区域上,这样每一个进程最终访问到的

物理地址空间都是彼此分开的。经过这种方式,就实现了进程间的地址隔离。仍是以实例说明,假设有两个进程 A 和 B ,进程 A 所需内存大小为 10M ,其虚拟地址空间分布在 0x00000000 到 0x00A00000 ,进程 B 所需内存为 100M ,其虚拟地址空间分布为 0x00000000 到 0x06400000 。那么按照分段的映射方法,进程 A 在物理内存上映射区域为 0x00100000 到 0x00B00000 ,,进程 B 在物理内存上映射区域为 0x00C00000 到 0x07000000 。因而进程 A 和进程 B 分别被映射到了不一样的内存区间,彼此互不重叠,实现了地址隔离。从应用程序的角度看来,进程 A 的地址空间就是分布在 0x00000000 到 0x00A00000 ,在作开发时,开发人员只需访问这段区间上的地址便可。应用程序并不关心进程 A 究竟被映射到物理内存的那块区域上了,因此程序的运行地址也就是至关于说是肯定的了。 图二显示的是分段方式

的内存映射方法。 

 

图二 分段方式的内存映射方法

      这 种分段的映射方法虽然解决了上述中的问题一和问题三,但并没能解决问题二,即内存的使用效率问题。在分段的映射方法中,每次换入换出内存的都是整个程序,这样会形成大量的磁盘访问操做,致使效率低下。因此这种映射方法仍是稍显粗糙,粒度比较大。实际上,程序的运行有局部性特色,在某个时间段内,程序只是访 问程序的一小部分数据,也就是说,程序的大部分数据在一个时间段内都不会被用到。基于这种状况,人们想到了粒度更小的内存分割和映射方法,这种方法就是分页 (Paging) 。  

3、分页

分页的基本方法是,将地址空间分红许多的页。每页的大小由 CPU 决定,而后由操做系统选择页的大小。目前 Inter 系列的 CPU 支持 4KB 或 4MB 的页大小,而 PC 上目前都选择使用 4KB 。按这种选择, 4GB 虚拟地址空间共能够分红 1048576 个页, 512M 的物理内存能够分为 131072 个页。显然虚拟空间的页数要比物理空间的页数多得多。

在 分段的方法中,每次程序运行时老是把程序所有装入内存,而分页的方法则有所不一样。分页的思想是程序运行时用到哪页就为哪页分配内存,没用到的页暂时保留在硬盘上。当用到这些页时再在物理地址空间中为这些页分配内存,而后创建虚拟地址空间中的页和刚分配的物理内存页间的映射。

下面经过介绍一个可执行文件的装载过程来讲明分页机制的实现方法。一个可执行文件 (PE 文件 ) 其实就是一些编译连接好的数据和指令的集合,它也会被分红不少页,在 PE 文件执行的过程当中,它往内存中装载的单位就是页。当一个 PE 文件被执行时,操做系统会先为该程序建立一个 4GB 的进程虚拟地址空间。前面介绍过,虚拟地址空间只是一个中间层而已,它的功能是利用一种映射机制将虚拟地址空间映射到物理地址空间,因此,建立 4GB 虚拟地址空间其实并非要真的建立空间,只是要建立那种映射机制所须要的数据结构而已,这种数据结构就是页目和页表。

当建立完虚拟地址空间所须要的数据结构后,进程开始读取 PE 文件的第一页。在 PE 文件的第一页包含了 PE 文件头和段表等信息,进程根据文件头和段表等信息,将 PE 文件中全部的段一一映射到虚拟地址空间中相应的页 (PE 文件中的段的长度都是页长的整数倍 ) 。这时 PE 文件的真正指令和数据尚未被装入内存中,操做系统只是根据 PE 文件的头部等信息创建了 PE 文件和进程虚拟地址空间中页的映射关系而已。当 CPU 要访问程序中用到的某个虚拟地址时,当 CPU 发现该地址并无相相关联的物理地址时, CPU 认为该虚拟地址所在的页面是个空页面, CPU 会认为这是个页错误 (Page Fault) , CPU 也就知道了操做系统还未给该 PE 页面分配内存, CPU 会将控制权交还给操做系统。操做系统因而为该 PE 页面在物理空间中分配一个页面,而后再将这个物理页面与虚拟空间中的虚拟页面映射起来,而后将控制权再还给进程,进程从刚才发生页错误的位置从新开始执行。因为此时已为 PE 文件的那个页面分配了内存,因此就不会发生页错误了。随着程序的执行,页错误会不断地产生,操做系统也会为进程分配相应的物理页面来知足进程执行的需求。

分页方法的核心思想就是当可执行文件执行到第 x 页时,就为第 x 页分配一个内存页 y ,而后再将这个内存页添加到进程虚拟地址空间的映射表中 , 这个映射表就至关于一个 y=f(x) 函数。应用程序经过这个映射表就能够访问到 x 页关联的 y 页了。

 

总结:

32位的CPU 的寻址空间是4GB , 因此虚拟内存的最大值为4GB , 而windows 操做系统把这4GB 分红2 部分, 即2G 的用户空间和2G 的系统空间, 系统空间是各个进程所共享的, 他存放的是操做系统及一些内核对象等, 而用户空间是分配给各个进程使用的, 用户空间包括用: 程序代码和数据, 堆, 共享库, 栈。

 

 

reference

相关文章
相关标签/搜索