内存对齐问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了内存对齐问题相关的知识,希望对你有一定的参考价值。

参考技术A

1.平台原因(移植原因): 不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能
在某些地址处取某些特定类型的数据,否则抛出硬件异常。
2.性能原因: 数据结构应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。(如果是对齐的,那么CPU不需要跨越两个操作字,不是对齐的则需要访问两个操作字才能拼接出需要的内存地址)

指针的大小一般是一个机器字的大小

通过Go语言的structlayout工具,可以得出下图

这些类型在之前的 slice 、 map 、 interface 已经介绍过了,也特意强调过,makehmap函数返回的是一个指针,因此map的对齐为一个机器字.

回头看看 sync.pool的防止copy的空结构体字段,也是放在第一位,破案了。

计算机结构可能会要求内存地址 进行对齐;也就是说,一个变量的地址是一个因子的倍数,也就是该变量的类型是对齐值。
函数Alignof接受一个表示任何类型变量的表达式作为参数,并以字节为单位返回变量(类型)的对齐值。对于变量x:

这是因为int64在bool之后未对齐。
它是32位对齐的,但不是64位对齐的,因为我们使用的是32位系统,因此实际上只是两个32位值并排在一起。

● 内存对齐是为了cpu更高效访问内存中数据
● 结构体对齐依赖类型的大小保证和对齐保证
● 地址对齐保证是:如果类型 t 的对齐保证是 n,那么类型 t 的每个值的地址在运行时必须是 n 的倍数。
● struct内字段如果填充过多,可以尝试重排,使字段排列更紧密,减少内存浪费
● 零大小字段要避免作为struct最后一个字段,会有内存浪费
● 32位系统上对64位字的原子访问要保证其是8bytes对齐的;当然如果不必要的 话,还是用加锁(mutex)的方式更清晰简单

图解go-内存对齐
doc-pdf

SSE向量化与内存对齐的关系

【中文标题】SSE向量化与内存对齐的关系【英文标题】:Relationship between SSE vectorization and Memory alignment 【发布时间】:2013-02-12 00:25:04 【问题描述】:

为什么我们需要为 SSE/AVX 对齐内存?

我经常得到的答案之一是对齐的内存加载比未对齐的内存加载快得多。那么,为什么这种对齐的内存加载比未对齐的内存加载要快得多?

【问题讨论】:

【参考方案1】:

这不仅仅特定于 SSE(甚至 x86)。在大多数架构上,加载和存储需要自然对齐,否则它们要么 (a) 生成异常,要么 (b) 需要两个或更多周期加上一些修复,以便透明地处理未对齐的加载/存储。在 x86 上,(b) 适用于

您可能想知道:为什么不使用这些 SSE 加载/存储指令的未对齐版本而不考虑对齐方式?答案是这些指令通常比对齐的指令慢得多,因为它们通常按照上述 (b) 的方式运行,这使得它们通常慢 2 倍或更多,除了最近的 Intel CPU,如 Core i7,其惩罚要小得多,但并非微不足道。

【讨论】:

请记住,即使在未对齐访问通常很快的现代内核上,跨页访问仍然很慢。如果您的缓冲区足够大且未对齐,它将包含页面交叉。 正确,并且由于未对齐的负载而跨越缓存行边界会导致更大的缓存占用空间,这也可能对性能产生负面影响。 好的,但是,为什么?我喜欢这个答案,但为什么会发生所有这些性能命中和缓存错误注册?换句话说,对齐解决了什么问题? @codekaizen:与所有事物一样,硬件设计涉及妥协——对于 CPU,这通常意味着在硅区域的有限资源与功能之间进行权衡。支持任意数据对齐需要大量的芯片来实现,并且可能不是一个特别有用的功能 - 芯片可以用于更有益的东西,比如另一个 ALU。

以上是关于内存对齐问题的主要内容,如果未能解决你的问题,请参考以下文章

关于C++的内存对齐

内存对齐与页面对齐

内存对齐以及如何关闭内存对齐

SSE向量化与内存对齐的关系

结构体内存对齐

C++ 类内存模型和对齐