内存字节对齐和 cpu 是什么关系?

比如有一个内存条,总容量为: 64 Bit
有一个 16 bitCPU

这个时候,cpu 读取内存只能是 [0,16)[16,32)[32,48) 这样吗?

不能是 [3,19)[6,22) 这样吗?

[0,16) 表示读取内存条第 0 个 bit(包含)到第 16 个 bit(不包含)
[3,19) 表示读取内存条第 3 个 bit(包含)到第 19 个 bit(不包含)

如果要读取 [3,19) 这样的地址范围的话,是不是要分成 [0,16)[16,32) 分成两次读取,是这样吗?

假设这个问题讨论的是现代 CPU,比如 intel 的 i9-12900k, AMD 的 5990x, Apple 的 m1 max,高通的 8 gen1
这些现代化的 64 bit 的 cpu,是不是必须是 [0,64)[64,128)[128,192) 按照 64 的倍数来读取内存?还是说他们是支持非整数倍操作内存的?(包括读和写)
阅读 2.7k
3 个回答

理论上可以这么读,但不经济,原因在于CPU并不直接和内存打交道,因为内存实在太慢...了。
CPU 通常是和1级2级3级缓存打交道,不得已才读写内存。读写内存通常是一整块一整块的读,这样效率高。这就像汽车的油箱和加油站的关系,加油费时间,但一次加一箱和加一升的时间差别不太大。发动机会首先从油箱里取,没有了才会去加油站,没人一次加一升。

那为什么一定要内存对齐呢?

简单地说,还是因为这么做效率高。磁盘存储是分块的,内存也是按页管理,CPU 也是按32/64/128位来寻址和处理数据。如果可以任意偏移读写,会有的大量的计算都要浪费在偏移处理上,硬件设计上也不容易。所以没人这么做。

这就好比做工业化的鸡蛋篓,一篓装32个,可以设计好机器可以很愉快地自动装载,但你这一篓非要装31个,为实现单拿出一个的需求,需要设计复杂得多的机器/算法/操作才能实现。提这样需求的人会被打的,所以没有人这么干。

没有特意地学习过操作系统,简单说下我的理解,

你当前的问题其实和内存的字节对齐没有什么直接的关系。

cpu只所以一段段的读取,这是由数据总线宽度决定的。比如数据总线的宽度是16位,则CPU一次只能而且也必须读取16位(读取完用不用是CPU的是,但读取的数据必然是16位)。
至于为什么是:0, 16, 32. 而不是:3, 5, 7, 9,我想有两方面决定。

  1. 由于计算机一次只能读取16位,而要保障0号可读,所以必须从0开始读。
  2. 计算机有着超强的2进制计算能力(加法运算器、移位运算),所以它获取 0,16,32,比获取3, 5, 7, 9要简单的多。

最后再说下块对齐:
还是以16位的数据总线为例,由于CPU一次能读取16位的数据过来,所以当一个数据的长度小于16位时,我们要保障CPU只与内存交互一次便可以获取到全部想的数据。这话听起来没毛病:比如生活中你一次能携带10KG的东西,此时有个任务是让你携带5KG过来,那么原则上你只需要跑一次。

我们假设当前CPU想要一个小于16位的数据(101),如果这么存:

0 1 2 3 4 5 6 x x 15 16 17 18
x x x x x x x x x  1  0  1  .

那么CPU就需要与内存交互两次数据,分别获取 0 - 15 以及 16 -31.

我想以上就是需要对齐的原因。

因为经过对齐以后,内存就会这么存这个数:

0 1 2 3 4 5 6 x x 15 16 17 18 19
x x x x x x x x x  . 1  0  1  .

此时,虽然第15位浪费了1个bit的空间利用,但可以保障CPU与内存交互一次(16 -31)可以获取到这个比16bit小的101数据。

内存对齐只是处理中提高速度的一般措施,而不是必须措施,数据的存储与使用要根据数据特性来,而不是根据CPU特性来。

不过现代很多处理中,会自动优化实现内存对齐,这主要是为了提高速度,而没有特别的意义,如果你的数据结构确实需要非对齐的处理,CPU肯定也是能处理的,不过运行速度肯定要下降很多。

你如果了解C的结构体、共用体,就可以知道数据在内存中的组织可以有很多方式,但有些方式速度方面的效率高,有些方式空间上的效率高,当前空间已经不在那么紧张情况下,优化方向多是速度优化,这时对齐来提高速度就是常见可选策略啦。

对于

假设这个问题讨论的是现代 CPU,比如 intel 的 i9-12900k, AMD 的 5990x, Apple 的 m1 max,高通的 8 gen1
这些现代化的 64 bit 的 cpu,是不是必须是 [0,64)、[64,128)、[128,192) 按照 64 的倍数来读取内存?还是说他们是支持非整数倍操作内存的?(包括读和写)

cpu 都是支持按位读写内存的,只是效率比整体的读写要低。

你看到很多语言有位操作指令,就是来干这些事情的。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题