1. 64位内存
64位系统最显著的优点是它可以使用超过4GB的内存。为什么32位的系统只能显示3G内存(实际上是3.25G)呢?这是由于系统本身的限制所造成的。32位系统对于内存的寻址能力总共就4G,而4G里还要放其他东西:比如系统 BIOS,输入输出设备的地址和设定,各类接口的设定和地址等等,这些地址和设定所占用的空间要达到700M左右,因此4G内存在32位中也只能显示出3G了。
1.1 虚拟内存
在早年的计算机中,地址的转换很单纯,有效地址就直接等于物理存储器的地址,这适合同一时间只有一个进程在运作。但Windows不会只有一个Window,多进程并存是现代计算机的基本情形。后来人们决定为每个进程划定一块专用内存区域,这样可以让多个进程同时运作。但这种分段方式会让内存在进程开关的过程中产生很多碎片,很多小块内存无法被利用。由于内存空间总是相对有限的,因此应用程序也不能疯狂的将所有东西直接塞进内存当中。同时也不能依赖硬盘这个缓慢的二级存储器去充当内存,那实在太慢了。为了调和这个矛盾,操作系统都引入了虚拟内存机制。
Windows的虚拟内存并非简单的指位于硬盘上的那个pagefile.sys文件,或者是在内存装不下的时候用于应急的“模拟内存”。在Windows系统中,任何一个进程都会被赋予其自己的虚拟地址空间,这是一种逻辑地址空间,并不存在实体,该虚拟地址空间可以覆盖了一个相当大的范围。对于一个32位进程,其可以拥有的虚拟地址空间为2^32=4GB,典型情况为2GB用户空间,2GB系统内核空间(最大可调整为3GB用户空间和1GB内核空间),这与安装了多少物理内存没有任何关系。每个进程的虚拟地址空间都会被标上各自的ID,这样两个进程之间的虚拟地址就不会互相干扰。虽然每一个32位进程可使用4GB的地址空间,但并不意味着每一个进程实际拥有4GB的物理地址空间或使用4GB物理内存,虚拟地址仅仅是一种逻辑地址。
应用程序自然不能总在看不见摸不着的虚拟地址里溜达,最终还是需要实实在在的物理存储器关联。应用程序会为其虚拟地址申请物理存储空间,这个空间通常小于应用程序的总虚拟空间。这里所说的物理存储器并不局限于计算机内存,还包括在磁盘空间上创建的页文件(pagefile.sys),存储空间大小为计算机内存和页文件存储容量之和(所以Windows自动管理时的pagefile.sys是很大的)。由于通常情况下磁盘存储空间要远大于内存的存储空间,因此页文件的使用对于应用程序而言确实相当于透明地增加了其所能使用的内存容量,只是速度慢了点。有了虚拟内存,程序本身就不用完全装入内存,或者完全存于硬盘,系统会将目前需要的部分读入内存处理,暂时不需要的就放在硬盘的页文件留作交换。不过CPU并不能直接去访问磁盘上的信息,每次磁盘访问都必须通过内存,所以若所需的内容在磁盘上的页文件中,就需要先加载到内存然后访问。
1.2 进程的虚拟地址空间
每个进程都有自己的虚拟地址空间,对于32位进程来说,这个地址空间的大小为4GB,因为32位指针可以表示从0x00000000到0xFFFFFFFF之间的任一值。指针在这个范围内可以有4 294 967 296个值,它覆盖了进程的4GB地址空间。对于64位进程来说,由于64位指针可以表示从0x00000000'00000000到0xFFFFFFFF'FFFFFFFF之间的任一值,因此这个地址空间的大小为16EB[i]。指针在这个范围内可以有18 446 744 073 709 551616 个值,它覆盖了进程的16EB的地址空间。每个进程都有自己的私有的地址空间,当进程中各线程运行时,它们只能访问属于该进程的内存,线程既看不到属于其他进程的内存,也无法访问它们。
虽然应用程序有这么大的地址空间可用,但是这只是虚拟地址空间——不是物理存储器。这个地址空间只不过是一个内存地址区间,为了能够正常读/写数据,还需要把物理存储器分配或映射到相应的地址空间,否则将导致访问违规(access violation)。
1.3 虚拟地址空间分区
每个进程的虚拟地址空间被划分成许多分区(partition)。由于地址空间的分区依赖于操作系统的底层实现,因此随着Windows内核的不同而略有变化。下表列出了各平台上对进程地址空间的分区。
分区 | X86 32位 Windows | 3 GB用户模式下的X86 32位 Windows | X64 64位 Windows
| IA-64 64位 Windows |
空指针 赋值 分区 | 0x00000000 0x0000FFFF | 0x00000000 0x0000FFFF | 0x00000000'00000000 0x00000000'0000FFFF | 0x00000000'00000000 0x00000000'0000FFFF |
用户模式 分区 | 0x00010000 0x7FFEFFFF | 0x00010000 0xBFFEFFFF | 0x00000000'00010000 0x000007FF'FFFEFFFF | 0x00000000'00010000 0x000006FB' FFFEFFFF |
64KB禁入 分区 | 0x7FFF0000 0x7FFFFFFF | 0xBFFF0000 0xBFFFFFFF | 0x000007FF'FFFF0000 0x000007FF'FFFFFFFF | 0x000006FB'FFFF0000 0x000006FB'FFFFFFFF |
内核模式 分区 | 0x80000000 0xFFFFFFFF | 0xC0000000 0xFFFFFFFF | 0x00000800'00000000 0xFFFFFFFF'FFFFFFFF | 0x000006FC'00000000 0xFFFFFFFF'FFFFFFFF |
表1 进程地址空间的分区
可以看到,32位Windows内核和64位Windows内核的分区基本一致,唯一的不同在于分区的大小和分区的位置。
[i] 1KB = 210;1MB = 220; 1GB = 230;1TB= 240;1PB = 250;1EB = 260.