七叶笔记 » golang编程 » Golang 优化结构体-极致地减少内存开销

Golang 优化结构体-极致地减少内存开销

你应该知道的简单数据对齐技术

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确实比其对应物花费的时间更少。

重新排序结构字段可以提高应用程序的内存使用率和速度。

想象一下,使用大量大型结构来维护一个广泛的应用程序,这将改变游戏规则。

结束

好吧,这就是这篇博文的内容。让我们以一个简单的号召性用语来结束这一切:

就这样吧,下次再说吧!

相关文章