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 程序的性能!

相关推荐
想用offer打牌2 小时前
MCP (Model Context Protocol) 技术理解 - 第二篇
后端·aigc·mcp
KYGALYX4 小时前
服务异步通信
开发语言·后端·微服务·ruby
掘了4 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
爬山算法4 小时前
Hibernate(90)如何在故障注入测试中使用Hibernate?
java·后端·hibernate
Moment5 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
Cobyte5 小时前
AI全栈实战:使用 Python+LangChain+Vue3 构建一个 LLM 聊天应用
前端·后端·aigc
程序员侠客行6 小时前
Mybatis连接池实现及池化模式
java·后端·架构·mybatis
Honmaple6 小时前
QMD (Quarto Markdown) 搭建与使用指南
后端
PP东7 小时前
Flowable学习(二)——Flowable概念学习
java·后端·学习·flowable
invicinble7 小时前
springboot的核心实现机制原理
java·spring boot·后端