Go结构体优化(对齐方式)

Go 语言和 C 语言类似,结构体的成员必须按照它们的对齐要求存储。编译器会自动填充对齐字节,确保每个字段的起始地址符合 CPU 的对齐规则。

示例

go 复制代码
package main

import (
    "fmt"
    "unsafe"
)

type A struct {
    a int8
    b uint32
    c int16
}

func main() {
    fmt.Printf("Offsetof(A.a) = %d\n", unsafe.Offsetof(A{}.a))
    fmt.Printf("Offsetof(A.b) = %d\n", unsafe.Offsetof(A{}.b))
    fmt.Printf("Offsetof(A.c) = %d\n", unsafe.Offsetof(A{}.c))
    fmt.Printf("Sizeof(A) = %d\n", unsafe.Sizeof(A{}))
}

/*
Output:
Offsetof(A.a) = 0
Offsetof(A.b) = 4
Offsetof(A.c) = 8
Sizeof(A) = 12
*/

内存布局

因为 b 需要4字节对齐,所以编译器会在 a 之后填充3个字节。又因为结构体的大小必须是其最大对齐方式(4字节)的整数倍,所以最终结构体 A 的大小为12个字节。

优化

go 复制代码
package main

import (
    "fmt"
    "unsafe"
)

type AOptimized struct {
    a int8
    c int16
    b uint32
}

func main() {
    fmt.Printf("Offsetof(AOptimized.a) = %d\n", unsafe.Offsetof(AOptimized{}.a))
    fmt.Printf("Offsetof(AOptimized.b) = %d\n", unsafe.Offsetof(AOptimized{}.b))
    fmt.Printf("Offsetof(AOptimized.c) = %d\n", unsafe.Offsetof(AOptimized{}.c))
    fmt.Printf("Sizeof(AOptimized) = %d\n", unsafe.Sizeof(AOptimized{}))
}

优化后内存布局

因为 c 需要2字节对齐,所以编译器会在 a 之后填充1个字节。此时结构体的实际大小为8个字节,刚好是最大对齐方式(4字节)的整数倍,所以最终结构体 A 的大小为8个字节。

结论

Go 结构体需要关注对齐

  • 和 C 语言一样,Go 结构体会自动填充来对齐字段。
  • 不合理的字段排列会浪费内存。
  • 使用 unsafe.Sizeof()unsafe.Offsetof() 了解结构体的内存布局。

结构体优化可以减少内存占用

  • 合理排序字段,减少填充。

合理优化结构体,可以减少内存占用,提高 Go 程序的性能!

相关推荐
天天摸鱼的java工程师2 分钟前
🔧 MySQL 索引的设计原则有哪些?【原理 + 业务场景实战】
java·后端·面试
snakeshe10106 分钟前
Maven核心功能与IDEA高效调试技巧全解析
后端
*愿风载尘*1 小时前
ksql连接数据库免输入密码交互
数据库·后端
溟洵1 小时前
Qt 窗口 工具栏QToolBar、状态栏StatusBar
开发语言·前端·数据库·c++·后端·qt
ppo921 小时前
MCP简单应用:使用SpringAI + Cline + DeepSeek实现AI创建文件并写入内容
人工智能·后端
创码小奇客1 小时前
Talos 使用全攻略:从基础到高阶,常见问题一网打尽
java·后端·架构
Re2751 小时前
ThreadLocal 入门:搞懂线程私有变量
后端
midsummer_woo2 小时前
基于spring boot的纺织品企业财务管理系统(源码+论文)
java·spring boot·后端
zc-code2 小时前
Spring Boot + @RefreshScope:动态刷新配置的终极指南
java·spring boot·后端
何中应2 小时前
EasyExcel使用(二:写出)
java·后端·maven·excel