内存对齐
1. 存取粒度
CPU 需要从内存中读取数据到寄存器中,计算完成之后再做输出等一系列操作。和物流一样,一辆飞机或者卡车一次不会只运输一个快递单,同理:
- CPU 不是一个字节一个字节地读取内存的,而是按照一定的大小来读取内存中的数据到寄存区。比如2字节、4字节、16字节等;
这就是 CPU 的存取粒度
2. 为什么需要内存对齐
有了存取粒度的前提,假设 CPU 存取粒度为 4 个字节,而所需要数据分别标记为 1、2、3、4。
如果没有内存对齐,那么显然所有的数据都是顺序乱序排列,每一个地址都会被用的很满,假设用 1 个字节的 char 类型来做填充。
那么,当 CPU 读取这 4 个字节时,就会存在三种情况:
如图:
无内存对齐
- 恰好从第一位开始读取
此时,CPU 通过一次读取就拿到了所需的 4 个数据,这是最完美的情况;
- 从第一位之前开始读取
- 从第一位之后开始读取
无论哪种情况出现,最终都需要读取两次,流程大致如图:
拼接数据
此时,相对于第一种情况,额外的操作有:
- 读取次数增加;
- 在不同的内存段中寻找并取出正确的数据;
- 数据的拼接;
- 如果需要取出的数据量很大,比如16字节、32、256等,复杂度成倍上升;
- CPU 的操作频率相当之快,这种多余的操作就会成指数级别地影响性能;
以上在没有内存对齐的情况下,CPU 能否单次操作就读取到所需要的全部数据,完全是随缘,此时就需要通过内存对齐来最大限度的减少这种多次读取的情况,所以内存对齐相当重要!!!
人为规定当数据少于 CPU 存取粒度时,最少给予数据一个存取粒度大小的字节数。
比如 CPU 存取粒度是 4 字节,数据作为一个整体,不足 4 个字节的数据补充到 4 或者 4 的倍数,各种不对齐的情况就会变成:
内存对齐
上图不同颜色表示一个完成的数据字段;
如此,CPU 都只需要一次就可以读取到全部数据。当所需数据为 8 字节时,也只需要 8 / 4 = 2 次;
3. 内存对齐的规则
- 结构体大小必须是最大成员变量大小的倍数;