32位和64位

来源:互联网 发布:c语言编的小游戏 编辑:程序博客网 时间:2024/04/29 06:44

32位和64位,x86和x64。

这样的概念肯定不会陌生,本文旨在理清楚它们之间那些非(mei)常(you)重(luan)要(yong)的细节。

要说清楚这些概念,先要了解一些基础知识。

什么是位(bit)?

位(bit)是计算机数据存储的最小单位。

计算机无法直接识别现实世界中的复杂数据,对于这些数据,都需要转换成其能够识别的电子信号。它将高电平识别为1,低电平识别为0,这就形成了一个基本的存储单元,该单元能够存储两个数据:1和0。

具体这个1或0代表的是一个数字、还是一个指令、亦或是一张图片一篇文章的一部分,在不同的场景下意义不同。总之呢,有了二进制,计算机可以存储数据了,而1位就指的是一个二进制位因此1位可以存储的数据量是2(0和1两个数据)。

下面是一个例子:

将一个十进制的数字11存储在计算机上,抛开类型、符号不谈,就应该下下面这个样子:
1 0 1 1
如何换算的?不是该文要讨论的内容。我们可以从最终的结果上看出11这个数字存储在计算机上会占用4位,或者说占用4bit。
注:上面的演算仅存在理论上,事实上该数字会占用更多的位数,不过不在本文的讨论范畴。

其他的存储单位

世界上没有一个货币仅用一种单位发放,人民币有元和角,美元也是如此。

计算机也是如此,它有多种单位来表示存储空间。

实际上对于计算机本身而言,真正存储数据的只有位(bit)。其他的存储单位是人类为了表达的便利加以区分的。
这是因为在不同的场景下存储空间占用差别过大,一个字符最多占16位,一个游戏可能占10^30。
相信你也看出来了,动不动数据差个30来个数量级也有点让人受不了,于是就诞生了各种各样的单位。

下面是一些单位的换算(很多单位肯定不会陌生):

  • 1TB = 1024GB
  • 1GB = 1024MB
  • 1MB = 1024KB
  • 1KB = 1024B
  • 1B = 8bit

在上面的换算中,倒数第二行的B有时候也写作byte(字节),在后文中会多次提到该单位。

有了这个换算关系,让你将你的硬盘的存储量(例如1TB)换算成位是不是很简单了呢?

1(TB) = 1024 × 1024 × 1024 × 1024 × 8 (bit)

操作系统对内存数据的管理

无论是硬盘还是内存,它们对数据的存储最终都是依靠二进制位完成的。

在内存中,所有的位是散列排列的,并没有组织成更大的单元,比如你的电脑当下内存条中的数据排列可能如下:

  • 101000001000111111010001010101101111111110000000001111100001111000000011111000001……

你能从上面的数据看出这些1和0代表的是什么数据吗?你能看出哪些数据是属于你正在玩的游戏,哪些是属于你正在浏览的网页吗?

做不到对吗?你做不到的其中一个原因是你不知道这些数据的分界在哪,就像一篇文章如果没有段落和标点符号,那么阅读难度自然会飙升,同时会产生很多歧义。

操作系统的一个重要功能就是对内存数据进行管理,它首先遇到的第一个问题是数据存取单位的问题。

你可能有些迷茫,使用bit不行吗?

不行!1个bit所包含的数据量太小(只有两个),如果一次取数据只取1bit,一次存数据也只存1bit,效率肯定会非常低下,要知道,IO(输入输出,存取数据都属于IO)操作可是非常消耗时间的。

那使用1GB作为存取单位可以吗?

也不行!1GB包含的数据量太大了,如果我仅仅只是想取一个数字出来运算却要消耗大量时间把不必要的数据取出来,也会非常浪费时间。

最终,操作系统选择了byte这个单位,1byte=8bit,不大也不小,对于大部分情况刚好合适。

所以,操作系统对数据存取的最小单位是byte

int a = 1;
在C#中,int类型在内存中占32位,无论的取值是多少都要占32位。而1byte=8位,换句话说,int类型在内存中会占4个字节。那么上面这句代码,操作系统会分4次将该数据存储到内存中,所以这不是一个原子操作。

操作系统将byte定义位存取数据的最小单位,在很大程度上解决了数据存取的效率问题,还有一个根本问题没有解决:

面对诸如这样的数据存储情况:

10100000 10001111 11010001 01010110 11111111 10000000 00111110 00011110 00000011 11100000 ……
注:现在跟之前不同的是,我每隔8位多了一个空格,这并不表示在内存中真的有空格,这只是让你清楚,自从操作系统定义了最小存取单元后,现在它知道了数据的分界。

但面对这样的数据,操作系统怎么知道那一个字节才是我们需要的数据呢?

于是操作系统为每个字节编个号,就像学号、工号一样,取数据的时候用这个编号去取,存数据的时候会给存放的数据一个新的编号。

这个编号,在计算机中叫做地址

内存寻址

计算机对于内存中每个字节的编号(地址),长度总是固定的。这就带来一个最大取址的问题。

举个例子:

如果你所在的学校使用6位的学号编排学生,那么使用这种位数的学号最多可以编排999999个学生,如果学生超过了这个数量,这种位数的学号就无能为力了。它最多就到999999,多了的学生管不了。
内存的地址编号也是一样,但不同的是,计算机中的地址编号也只能使用二进制,那么二进制的位数就决定了最大编号。
例如,两位的二进制编号只能为编号4byte的数据,它们的编号分别是:
00,01,10,11

所以,我们可以说操作系统如果使用两位的编号(我们姑且将其叫做2位操作系统),可以编排4byte的数据(我们姑且叫做寻址范围为4byte)。以此类推:

  • 2位操作系统的寻址范围=2^2 byte
  • 4位操作系统的寻址范围=2^4 byte
  • ……
  • 32位操作系统的寻址范围=2^32 byte = 4 GB
  • 64位操作系统的寻址范围=2^64 byte = 17179869184 GB

写到这里,如果你看懂了上面的知识,应该就明白了:

N位的操作系统指的是它对内存的寻址能力

那你或许还有疑问,既然寻址位数越多,能够支持的内存就越大,那为什么不将寻址位数一开始就做很大呢?

这就牵扯到另一个话题————CPU的寻址。

CPU的寻址和X86指令集

操作系统再NB,最终也得将指令转交给CPU执行,那么如果操作系统是64位的,但CPU却只支持32位的寻址,不要说这个操作系统安装不起,就算安装上了也是白搭————就好像CPU是大脑,操作系统是四肢,大脑已残,四肢发达并没有用。

那CPU一开始怎么不做成很大的寻址范围呢?

因为技术和成本原因,在每个时期的工业水平上,往几寸大的CPU上增加一个量级的寻址范围,都是一件极具难度的挑战,所以往往在每个时期CPU的寻址位数是不一样的。

但这样总不是个办法,如果每个时期CPU的寻址位数都不一样,那么可以想象,在历史上的每个时期,各个CPU开发商都不得不为每一种CPU制定一套指令集,操作系统靠调用这些指令集来使用CPU资源。那么这样一来,就会出现当新的寻址能力更强的CPU出现后,将无法兼容现有软件的问题。

该如何解决呢?能否有一个能够一直兼容按照旧CPU开发的操作系统或软件的指令集呢?

这就是X86指令集!(实际上它的兼容性也没有理论上那样好,前几年用过64位win7的用户应该有所体会)

这是一套寻址范围可变的指令标准,理论上兼容各种长度的地址。要知道,X86指令集出现的时候,还是16位CPU的天下,而直到后来的32位大行其道时,X86指令集仍然发挥着作用。而且在32位CPU在世的期间,一直都沿用的是X86指令集,因此,现在习惯上也把X86作为32位的代名词。

紧接着,64位出现了,这一代的CPU给X86指令集带来了很大的冲击,X86的发明者Inter公司一度决定完全抛弃X86而研发新的指令集。可就在Inter犹豫时,AMD率先推出X86-64指令集(简称X64),这套指令集不仅基本兼容之前的X86指令,同时扩展出不少64位新指令。

然后微软表示操作系统将支持X64,这样一来,Inter不得不也跟着沿用X64指令集。

事情就是这么个事情,情况就是这么个情况。因为前两天被人问道32位和64位的区别,发现自己很多概念已经变得模糊。所以利用空闲时间整理了一下,就算给自己一个备忘吧。

0 0