所谓虚拟地址空间,就是程序可以使用的虚拟地址的有效范围。虚拟地址和物理地址的映射关系由操作系统决定,相应地,虚拟地址空间的大小也由操作系统决定,但还会受到编译模式的影响。
这节我们先讲解 CPU,再讲解编译模式,让大家了解编译器是如何配合 CPU 来提高程序运行速度的。
CPU 的数据处理能力
CPU 是计算机的核心,决定了计算机的数据处理能力和寻址能力,也即决定了计算机的性能。CPU 一次(一个时钟内)能处理的数据的大小由寄存器的位数和数据总线的宽度(也即有多少根数据总线)决定,我们通常所说的多少位的 CPU,除了可以理解为寄存器的位数,也可以理解数据总线的宽度,通常情况下它们是相等的。
数据总线位于主板之上,不在 CPU 中,也不由 CPU 决定,严格来讲,这里应该说 CPU 能够支持的数据总线的最大根数,也即能够支持的最大数据处理能力,为了表达方便,本文才使用“CPU 的数据总线”这一说法。
数据总线和主频都是 CPU 的重要指标:数据总线决定了 CPU 单次的数据处理能力,主频决定了 CPU 单位时间内的数据处理次数,它们的乘积就是 CPU 单位时间内的数据处理量。
我们常常听说,CPU 主频在计算机的发展过程中飞速提升,从最初的几十 KHz,到后来的几百 MHz,再到现在的 4GHz,终于因为硅晶体的物理特性很难再提升,只能向多核方向发展。在这个过程中,CPU 的数据总线宽度也在成倍增长,从早期的 8 位、16 位,到后来的 32 位,现在我们计算机大部分都在使用 64 位 CPU。
需要注意的是,数据总线和地址总线不是一回事,数据总线用于在 CPU 和内存之间传输数据,地址总线用于在内存上定位数据,它们之间没有必然的联系,宽度并不一定相等。实际情况是,地址总线的宽度往往随着数据总线的宽度而增长,以访问更大的内存。
1)16位CPU
早期的 CPU 是 16 位的,一次能处理 16Bit(2 个字节)的数据。这个时候计算机产业还处在早期,个人电脑也没有进入千家万户,也没有提出虚拟地址的概念,程序还是直接运行在物理内存上,操作系统对内存的管理非常简陋,程序员轻易就能编写一个恶意程序去修改其他程序的内存。
学过汇编的同学应该知道,典型的 16 位处理器是 Intel 8086,它的数据总线有 16 根,地址总线有 20 根,寻址能力为 2^20 = 1MB。
2)32 位 CPU
随着计算机产业的进步,出现了 32 位的 CPU,一次能处理 32Bit(4 个字节)的数据。这个时候就提出了虚拟地址的概念,并被应用到 CPU 和操作系统中,由它们共同完成虚拟地址和物理地址的映射,这使得程序编写更加容易,运行更加安全。
典型的 32 位处理器是 Intel 的 80386 和 Intel Pentium 4(奔腾 4):80386 的数据总线和地址总线宽度都是32 位,寻址能力达 4GB;Pentium 4 的地址总线宽度是 36 位,理论寻址能力达 64GB。
3)64位CPU
现代计算机都使用 64 位的 CPU,它们一次能处理 64Bit(8 个字节)的数据。典型的 64 位处理器是 Intel 的Core i3、i5、i7 等,它们的地址总线宽度为 40~50 位左右。64 位 CPU 的出现使个人电脑再次发生了质的飞跃。
实际支持的物理内存
CPU 支持的物理内存只是理论上的数据,实际应用中还会受到操作系统的限制,例如,Win7 64 位家庭版最大仅支持 8GB 或 16GB 的物理内存,Win7 64 位专业版或企业版能够支持到 192GB 的物理内存。
Windows Server 2003 数据中心版专为大型企业或国家机构而设计,可以处理海量数据,分为 32 位版和 64位版,32 位版最高支持 512GB 的物理内存,这显然超出了 32 位 CPU 的寻址能力,可以通过两次寻址来实现。
编译模式
为了兼容不同的平台,现代编译器大都提供两种编译模式:32 位模式和 64 位模式。
32位编译模式
在 32 位模式下,一个指针或地址占用 4 个字节的内存,共有 32 位,理论上能够访问的虚拟内存空间大小为2^32 = 0X100000000 Bytes,即 4GB,有效虚拟地址范围是 0 ~ 0XFFFFFFFF。
也就是说,对于 32 位的编译模式,不管实际物理内存有多大,程序能够访问的有效虚拟地址空间的范围就是 0~ 0XFFFFFFFF,也即虚拟地址空间的大小是 4GB。换句话说,程序能够使用的最大内存为 4GB,跟物理内存没有关系。
如果程序需要的内存大于物理内存,或者内存中剩余的空间不足以容纳当前程序,那么操作系统会将内存中暂时用不到的一部分数据写入到磁盘,等需要的时候再读取回来,这在《载入内存,让程序运行起来》中已经讲到。而我们的程序只管使用 4GB 的内存,不用关心硬件资源够不够。
如果物理内存大于4GB,例如目前很多PC机都配备了8GB的内存,那么程序也无能为力,它只能够使用其中的4GB.
64位编辑模式
在 64 位编译模式下,一个指针或地址占用 8 个字节的内存,共有 64 位,理论上能够访问的虚拟内存空间大小为 2^64。这是一个很大的值,几乎是无限的,就目前的技术来讲,不但物理内存不可能达到这么大,CPU 的寻址能力也没有这么大,实现 64 位长的虚拟地址只会增加系统的复杂度和地址转换的成本,带不来任何好处,所以 Windows 和 Linux 都对虚拟地址进行了限制,仅使用虚拟地址的低 48 位(6 个字节),总的虚拟地址空间大小为 2^48 = 256TB。
需要注意的是:
32 位的操作系统只能运行 32 位的程序(也即以 32 位模式编译的程序),64 位操作系统可以同时运行 32 位的程序(为了向前兼容,保留已有的大量的 32 位应用程序)和 64 位的程序(也即以 64 位模式编译的程序)。
64 位的 CPU 运行 64 位的程序才能发挥它的最大性能,运行 32 位的程序会白白浪费一部分资源。
目前计算机可以说已经进入了 64 位的时代,之所以还要提供 32 位编译模式,是为了兼容一些老的硬件平台和操作系统,或者某些场合下 32 位的环境已经足够,使用 64 位环境会增大成本,例如嵌入式系统、单片机、工控等。
这里所说的 32 位环境是指:32 位的 CPU + 32 位的操作系统 + 32 位的程序。
另外需要说明的是,32 位环境拥有非常经典的设计,易于理解,适合教学,现有的很多资料都是以 32 位环境为基础进行讲解的。本教程也是如此,除非特别指明,否则都是针对 32 位环境。相比于 32 位环境,64 位环境的设计思路并没有发生质的变化,理解了 32 环境很容易向 64 位环境迁移。
开启 64 位编译模式
以 VS2010 为例,创建工程后默认是 32 位的,如下图所示:
“Win32”表示 32 位编译模式。如果要以 64 位的方式编译,就需要新增编译模式,如下图所示:
选择“配置管理器”,弹出如下的对话框:
在“活动解决方案平台”下选择“新建”,弹出下面的对话框:
在下拉菜单中选择“x64”,即可新增 64 位编译模式。现在,我们就可以在两种编译模式之间进行切换了:
将下面的代码复制到源文件中:
1. #include <stdio.h>
2. #include <stdlib.h>
3. int a;
4. int main(){
5. int *p = &a;
6. printf("%#X, %d\\n", p, sizeof(int*));
7.
8. system("pause");
9. return 0;
10. }
在 Win32 编译模式下的结果: 0XB715C, 4
在 x64 编译模式下的结果: 0X3FF39740, 8
标签:32,虚拟地址,C语言,编译,64,内存,CPU From: https://blog.csdn.net/qq_45398836/article/details/145119423