1.2 “64-bit”的本质
1.2.1 什么是“64-bit”
“32-bit”是指在并行情况下可被处理或传输的bit位的个数,也可指在某种数据格式下一个简单元素所使用的bit位的个数,这些个数,就是32个。这个术语被用来表示微处理器上寄存器的宽度。
同理,“64-bit”,就是CPU上寄存器可存储64个bit表示的数。
1.2.2 “64-bit”本质
人类认识事物的一个基本原理是“数个数”。例如,远古时代,狩猎者打猎回来,可能带回一只野山羊、也可能带回几只野鸡。数个数是把事物当作整体看待的,于是我们有了“整数”的概念。“64-bit”就是一个整体,只是这个整体的盒子由64个小方格组成,每个小方格只能放入或不放入东西(或称为:每个小格子只能放入“1”或“0”),用“1”和“0”表示“有”和“无”, 64个小格子通过“1和0”的组合,我们就能表示“2的64次方”个组合,每个组合可以表示不同的意义,这就是编码。如果把这样的组合用来表示一个线性的范围,那么就能表示“2的64次方”个盒子组成的范围,每个盒子有自己不同的标识,即有不同的地址,这种表示方式就叫做“直接寻址”[1]。
也就是说,“64-bit”的计算机,能够直接在“2的64次方”个小盒子里找东西。“32-bit”的计算机,能够直接在“2的32次方”个小盒子里找东西,这显然比“64-bit”小得多。“64-bit”显著提高了计算机的管理“疆域”,封疆大吏,管辖范围辽阔,自然比“32-bit”富有优势。
“64-bit”的计算机通过“直接寻址”能管理的内存就可达到“2的64次方”bit,即16TB。这是第一点,计算机本身的物理特性就赋予了其超强的能力。
题外话:“64-bit”是寻找地址的基本数量单位,也是“64-bit”计算机存储数据的基本单位,这样,我们所知道的“short int”这样的数据,显然是用不了“64个”这么多的小格子的,既然用不了,那么剩余的小格子怎么办?要么浪费、要么填充其他数据。如果填充其他数据,就意味着在一个“64-bit”的小盒子里放多次不同的数据,而这样的数据是要从外存读到内存的,如果把一个小盒子放满,就势必存放多次;如果找出这些小个头数据,这就要查找多次;对于放和找这些操作,很是浪费时间,于是,内存浪费的现象就产生了,小格子不满就不满吧,浪费一点空间,节省一些额外的操作时间,这就是我们经常说得“内存对齐”。如果是同样的数据,有不同的数据类型,在“64-bit”的计算机上,将可能比“32-bit”的计算机浪费更多的内存空间。
然而,我们都知道,计算机管理内存和外存本质上是一样的,“32-bit”的计算机只能管理4GB内存,那么我们常用的硬盘也应该是这样大的一个值,为什么我们的硬盘却能达到比4GB更大的范围呢?
呵呵呵,这个问题很有意思,接下来该操作系统登场了。
操作系统是个软件,软件能在硬件的基础上发挥更大才智。人类擅于在有限的人生中为无限的事业奋斗,有限的才智总是能发挥出无穷的力量。于是,我们有了“间接寻址”的概念。间接寻址,其实就是一个带根的倒立的树,根节点是一个“2的64次方”个小盒子,每个小盒子的小格子可以指向另外的一个拥有“2的64次方”个小盒子,这样一层又一层,子子孙孙无穷匮也。于是,通过间接寻址,我们可以表示无穷的范围,计算机也可以管理无穷的存储空间。所以,在32-bit时代,我们能使用大容量硬盘就可以理解了。
这是第二点,操作系统通过间接寻址为计算机赋予了更为强大的管理能力。通过直接寻址和间接寻址(即:通过硬件和操作系统),“64-bit”的意义就表现为“可管理的空间增大”。
那么,“可管理的空间增大”又有什么意义呢?最直接的表现就是:可用内存增大了,操作系统不必和应用程序抢内存了;较之以往更多数据可被调入内存;大量数据在内存中可被操作的机会增多了,这样,就节省了大量的I/O。于是,用户感觉系统速度快了。
但是,是不是“64-bit”的应用一定比“32-bit”的应用快呢?回答是“不一定”。
如果应用程序只利用较少的内存,比如说小于2G,那么,这样的应用在“64-bit”机器上运行是看不出有什么优势的,原因是大内存不能被利用上。只有有效使用了大内存这一优势,性能才能得以发挥。在“32-bit”的机器上,最大寻址空间是4G,所以,从理论上讲,对于内存要求小于4G的应用,即使移植到“64-bit”的机器上,性能也不会有明显提高的。
另外,还得注意,机器支持的最大寻址空间并不表明任何程序都可以寻址到理论上限值的空间,这是因为操作系统通常还要使用一部分空间。比如,“32-bit”Windows系统下,操作系统至少保留了1G左右的空间供自己使用。这在“64-bit”的操作系统下道理同样。并不是可以寻址到理论上限值的空间。
比如,SQL Server2000用于Itanium的64位版本支持高达512GB的内存,并且不限制数据结构在地址空间的用户部分的驻留位置,这说明,即使物理内存很大,许多软件未必能用得上。软件自己的能力总要和外部客观条件完全相适应才能获得较高的性价比。
1.2.3 32-bit与64-bit的比较
|
32-bit |
64-bit |
寻址最大值 |
4GB |
16EB[2] |
值的个数 |
4,294,967,296 |
18,446,744,073,709,551,616 |
寻址范围 |
0x00000000-0xFFFFFFFF |
0x00000000’ 00000000-0xFFFFFFFF’ FFFFFFFF |
1.2.4 数据模型
其实,“x-bit”也代表数据的表示方式上。对于数据的表示,是用多少个bit来表示一个数据类型,这取决于机器的硬件,也取决于编译器[3]。“表1 数据模型和bit位对比表”显示了主流的机器所支持的数据类型所占用的bit长度。
表1 数据模型和bit位对比表
语言 |
x-bit |
Data model[4] |
short |
char |
int |
long |
long long |
pointers |
C C++ |
64 |
LP64[5] |
16 |
8 |
32 |
64 |
64 |
64 |
ILP64 |
16 |
8 |
64 |
64 |
64 |
64 |
||
SILP64 |
64 |
8 |
64 |
64 |
64 |
64 |
||
LLP64[6] |
16 |
8 |
32 |
32 |
64 |
64 |
||
32 |
LP32[7] |
16 |
8 |
16 |
32 |
- |
32 |
|
ILP32 |
16 |
8 |
32 |
32 |
- |
32 |
||
Java[8] |
|
- |
16 |
8 |
32 |
64 |
- |
- |
说明 |
1) I = Integer L = Long P = Pointer 2) 32-bit的机器,主要使用ILP32数据模型 3) 64-bit的机器,Microsoft使用LLP64数据模型;Linux系列多使用LP64数据模型 4) 如“LP64”指long和pointer为64bit |
1.2.5 示例
typdef struct node {
long count;
char class;
struct node *left;
short id;
struct node *right;
} Node;
假设有如上结构,如果数据模型是ILP32,则sizeof(Node) 的值是20字节,而使用LP64数据模型时,sizeof(Node) 的值是40字节。这完全是内存对齐的结果。因为在这个结构上,最大的数据类型是long和node指针,所以内存对齐依据它们,对于ILP32,则应是5×4字节;对于LP64,则应是5×8字节。
[1] 在一个处理器上。寄存器通常分为3种,一是整数寄存器。二是浮点数寄存器,三是其他的寄存器。在这些寄存器中,只有整数寄存器才能用于指针的计算。浮点数寄存器是表达不了地址范围的。
[2] EB,百亿亿字节。
[3] 为什么说“也取决于编译器”?因为编译器负责把代码翻译为本地机器(本类型硬件)上可执行的机器码。
[4] http://www.unix.org/version2/whatsnew/lp64_wp.html
[5] 支持者:Solaris, AIX, HP, Linux, Mac OS X, FreeBSD, and IBM z/OS native compilers
[6] 支持者:Microsoft's VC++ compiler
[7] 支持者:Apple Macintosh
[8] 无论是32位还是64位的JDK,其数据类型的长度是不会发生变化的。如,在Java语言中,对于int定义的类型,一定是32位的。这一点不依赖于操作系统,也不依赖于计算机对数据类型的支持,Java的虚拟机屏蔽了操作系统的差别。这给Java代码的安全性和可移植性带来好处。同样的道理,诸多软件都定义了自己的数据类型,这样能够有效保持数据的一致性,且能屏蔽硬件和操作系统带来的数据类型的差异,比如,数据库定义了int、char、varchar等诸多数据类型,其道理同语言中定义的数据类型的道理是一致的。