你应该知道的简单数据对齐技术
Pexels上的Mike拍摄的照片
如果您以前用 Golang 编写过,那么您很可能已经看到并实现了类型 — 结构。
您可能不知道的是,通过简单地重新排序结构中的字段,您可以极大地提高 Go 程序的速度和内存使用量!
难以置信?让我们切入正题!
简单演示 type BadStruct struct {
age uint8
passportNum uint64
siblings uint16
}
type GoodStruct struct {
age uint8
siblings uint16
passportNum uint64
}
在上面的代码片段中,我们创建了两个具有 相同 字段的结构。让我们编写一个简单的程序来分别输出它们的内存使用情况。
// Output
Bad struct is 24 bytes long
Good struct is 16 bytes long
如您所知,它们在内存使用方面有所不同。
发生了什么导致两个完全相似的结构消耗不同数量的字节?
答案在于数据在计算机内存中的排列方式。
简而言之,数据结构对齐。
数据结构对齐Pexels上的SHVETS制作拍摄的照片
CPU 以字大小而不是字节大小读取数据。
64 位系统中的一个字为 8 个字节,而 32 位系统中的一个字为 4 个字节。
简而言之,CPU 以字长的倍数读取地址。
想象一下使用 64 位系统。为了获取变量passportNum,我们的 CPU 需要两个周期而不是一个周期来访问数据。
第一个周期将获取内存 0 到 7,随后的周期将获取其余部分。
把它想象成一个笔记本,每页只能存储一个字大小的数据,在这种情况下,是 8 个字节。如果passportNum分散在两个页面上,则需要两次翻转才能检索完整的数据。
这是低效的。
因此,需要数据结构对齐——计算机将数据存储在一个地址等于数据大小的倍数。
一个 4 字节的数据只能从内存地址 0 或 4 开始
例如,一个 2 字节的数据可以存储在内存 0、2 或 4 中,而一个 4 字节的数据可以存储在内存 0、4 或 8 中。
通过简单地对齐数据,计算机确保passportNum可以在一个 CPU 周期内检索到 var。
数据结构填充Pexels上的Angela Roma拍摄的照片
填充是实现数据对齐的关键。
计算机在数据结构之间用额外的字节填充数据以对齐它们。
这就是额外内存的来源!
让我们重温一下我们的BadStructand GoodStruct。
GoodStruct消耗更少的内存仅仅是因为它拥有比 . 更好的结构字段顺序BadStruct。
由于填充,两个 13 字节的数据结构分别变成了 16 字节和 24 字节。
因此,您只需重新排序结构字段即可节省额外的内存!
为什么这有关系?百万美元的问题来了,你为什么要关心这个?
嗯,两个方面,速度和内存使用。
让我们做一个简单的基准测试来证明它!
我们通过循环遍历数组并将结构字段之一添加到任意变量来对GoodStructand进行基准测试。BadStruct
从结果中您可以看出,遍历GoodStruct确实比其对应物花费的时间更少。
重新排序结构字段可以提高应用程序的内存使用率和速度。
想象一下,使用大量大型结构来维护一个广泛的应用程序,这将改变游戏规则。
结束好吧,这就是这篇博文的内容。让我们以一个简单的号召性用语来结束这一切:
就这样吧,下次再说吧!