大家好,我是煎鱼。

在 Go 这一门编程语言中,我们时常会看到一些 Go 面试题或结构体的知识讲解,主要是针对内存对齐这一块的知识点。

这次 Go1.23 新版本中也针对这块进行了一些补全,分享给大家,一起学习和进步!

背景

Go 在对于结构体(struct)的布局规则描述得相当简略。在现实环境中,大多数都是由需要准备面试的同学、感兴趣的同学研究后分析在社区内分享出来。

但在实践中,由于结构体在极少数情况下需要与平台 API 进行交互,Go 的实现被严格限制,必须遵循平台的布局和对齐规则。

当这些规则与 Go 的默认设置不一致时,例如:ppc64le 平台上,float64 字段的平台对齐方式与 Go 默认的对齐方式不同,就可能引发兼容性问题。

这种情况迫使 Go 在那些约束条件与其它平台常见的情况不同的平台上做出权衡,或者可能引发问题,阻碍了可以节省内存和提高垃圾回收效率的字段重新排序优化。

Go1.23 新标准库 structs

本次 Go1.23 新增了一个标准库 structs,与 strings、bytes 和 slices 几个库并行,本次有着特殊的使用作用。

这个新库现阶段只有一个东西,那就是核心的 HostLayout 结构体:

package structs

// HostLayout, as a field type, signals that the size, alignment,
// and order of fields conform to requirements of the host
// platform and may not match the Go compiler’s defaults.
type HostLayout struct {}

HostLayout 用于声明和指定结构体采用主机的内存布局方式。当结构体包含 HostLayout 类型的字段时,其在内存中的布局将遵循主机的期望,一般与主机的 C 应用二进制接口(ABI)保持一致

值得注意的是,HostLayout 仅影响其所在的结构体本身的布局,而不影响结构体内部其他结构体字段的布局,也不会影响包含这种特殊布局结构体的其他结构体。

本次新增加的 HostLayout 将会作为字段类型使用,该字段在使用时建议命名为下划线("\_"),并放在结构体定义的最开始位置。

具体的用法例子,如下代码:

// 通过 HostLayout 指定结构体布局方式
type HasHostLayout struct {
    _ structs.HostLayout
   // 煎鱼正在干些什么...
   ...
   SomeField   SomeType
}

// 正常,无指定结构体布局方式
type SomeType struct {
   a, b  int8
   x int32
   c, d int8
}

var x SomeType
var y HasHostLayout

var ap []*SomeType = []*SomeType{&x, &y.SomeField}
...

用法的重点:放在在结构体字段定义的第一个位置、使用 _ structs.HostLayout 进行初始化声明。以此即可指定结构体采用主机的内存布局方式。

总结

Go 的结构体内存布局是不少人研究和参考的对象之一,因为很多同学希望能够拿到最节省内存性能的方式。

但是实际上 Go 缺省的布局方式在不同的 OS 平台中,也有水土不服的。软件工程没有银弹。

本次 Go1.23 新增的 structs.HostLayout 有效的给 Go 程序员自定义结构体的内存布局打开了一个 “后门”,能够根据自己真实的主机平台情况进行定制化的结构体内存决策。

  • 本文作者:煎鱼
  • 公众号:脑子进煎鱼了
  • 联系方式(微信号):cJY0728(加我拉你进技术交流群)
文章持续更新,可以微信搜【脑子进煎鱼了】阅读,本文 GitHub github.com/eddycjy/blog 已收录,学习 Go 语言可以看 Go 学习地图和路线,欢迎 Star 催更。

推荐阅读


煎鱼
8.4k 声望12.8k 粉丝