在使用Golang进行内存分配时,我们需要遵循一系列规则 。在深入了解这些规则之前,我们需要先了解变量的对齐方式 。
Golang的unsafe包中有一个函数Alignof,签名如下:
func Alignof(x ArbitraryType) uintptr
【Go 内存分配:结构体中的优化技巧】对于任何类型为v的变量x,AlignOf函数会返回该变量的对齐方式 。我们将对齐方式记为m 。现在,Golang确保m是满足变量x的内存地址 % m == 0的最大可能数,也就是说 , 变量x的内存地址是m的倍数 。
让我们来看看一些数据类型的对齐方式:
- byte, int8, uint8 -> 1
- int16, uint16 -> 2
- int32, uint32, float32, complex64 -> 4
- int, int64, uint64, float64, complex128 -> 8
- string, slice -> 8
为了更好地理解结构体内存分配的情况,我们将使用unsafe包中的另一个函数Offsetof 。该函数返回字段相对于结构体起始位置的位置,换句话说,它返回字段起始位置与结构体起始位置之间的字节数 。
func Offsetof(x ArbitraryType) uintptr
为了更好地理解结构体内存分配,让我们以一个示例结构体为例:type Example struct {a int8b stringc int8d int32}
现在,我们将找出类型为Example的变量所占用的总内存,并尝试优化分配 。var v = Example{a: 10,b: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus rhoncus.",c: 20,d: 100,}fmt.Println("字段a的偏移量:", unsafe.Offsetof(v.a)) // 输出:0fmt.Println("字段b的偏移量:", unsafe.Offsetof(v.b)) // 输出:8fmt.Println("字段c的偏移量:", unsafe.Offsetof(v.c)) // 输出:24fmt.Println("字段d的偏移量:", unsafe.Offsetof(v.d)) // 输出:28
现在,问题出现了:“为什么结构体中字段b的偏移量是8?它应该是1,因为字段a的类型是int8,只占用1个字节 。”回到字符串数据类型的对齐方式,它的值为8 , 这意味着地址需要被8整除,因此在其中插入了7个字节的“填充”,以确保这种行为 。为什么字段c的偏移量是24?字段b中的字符串看起来比16个字节要长得多,如果字符串的偏移量是8,那么字段c的偏移量应该更大一些 。
上述问题的答案是,在Go中,字符串并不是在结构体内的同一位置分配内存的 。有一个单独的数据结构来保存字符串描述符,并且该字符串描述符以原地方式存储在结构体中,用于类型为string的字段 , 该描述符的大小为16个字节 。
现在,让我们来看看unsafe包中的另一个函数Sizeof 。正如其名称所示,该函数估计并返回类型为x的变量所占用的字节数 。
注意:它是根据结构体中可能存在的不同大小的字段来估计大小的 。
func Sizeof(x ArbitraryType) uintptr
现在 , 让我们来看看我们的结构体Example的大小 。fmt.Println("Example的大?。?quot;, unsafe.Sizeof(v)) // 输出:32
我们如何优化这个结构体以最小化填充呢?为了优化这个结构体的内存,我们将查看不同数据类型的对齐方式,并尝试减少填充 。让我们尝试将两个int8类型的字段放在一起 。
type y struct {a int8c int8b stringd int32}var v = y{}fmt.Println("字段a的偏移量:", unsafe.Offsetof(v.a)) // 输出:0fmt.Println("字段b的偏移量:", unsafe.Offsetof(v.b)) // 输出:8fmt.Println("字段c的偏移量:", unsafe.Offsetof(v.c)) // 输出:1fmt.Println("字段d的偏移量:", unsafe.Offsetof(v.d)) // 输出:24fmt.Println("Example的大?。?quot;, unsafe.Sizeof(v)) // 输出:32
太棒了 , 我们去掉了一些填充,但是为什么大小仍然是32?大小应该是1(a)+ 1(c)+ 6(填充)+ 16(b)+ 4(d)= 28现在,当结构体的最后一个字段与架构的对齐要求不完全一致时,会在最后一个字段之后添加填充 , 以确保结构体的整体大小是其字段中最大对齐要求的倍数 。因为字符串数据类型的最大对齐方式为8,所以额外添加了填充,使大小成为8的倍数 , 即在末尾填充了4个字节 , 使大小为32字节 。
我们能否进一步减少填充,使其更加优化?
让我们尝试通过移动字段位置来实现 。
推荐阅读
- 笔记本电脑性能分析:处理器、内存、硬盘和显卡的深度解读
- 能咋的看电脑内存,怎么查看电脑内存条加装成功没有
- 技嘉主板如何设置内存频率,技嘉b85主板怎么设置内存频率
- 古代建筑结构有哪些 古代建筑结构有哪些种类
- 如何清理抖音极速版存储空间,抖音如何清理内存减少内存空间
- sdhc卡是什么卡,闪迪内存卡后面的HC I是什么意思
- 离婚股份怎么分配
- QLORA:大模型微调的内存高效方法
- 微信内存优化:释放大量空间,提升使用体验
- 手机内存清理的正确方法:你做对了吗?