Golang优化之内存对齐
Posted 咖啡色的羊驼
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Golang优化之内存对齐相关的知识,希望对你有一定的参考价值。
前文
话说今天在用uintptr进行指针运算的时候,突然想起来有个内存对齐的东西,那么对这个uintptr计算是否会有影响?
带着疑问,开始吧。
你将获得以下知识点:
1.什么是内存对齐?
2.为什么需要内存对齐?
3.如何进行内存对齐?
4.golang的内存对齐如何体现?
5.如何利用内存对齐来优化golang?
正文
1.什么是内存对齐?
在想象中内存应该是一个一个独立的字节组成的。像这样:
事实上,人家是这样的:
内存是按照成员的声明顺序,依次分配内存,第一个成员偏移量是0,其余每个成员的偏移量为指定数的整数倍数(图中是4)。像这样进行内存的分配叫做内存对齐。
2.为什么需要内存对齐?
原因有两点:
平台原因
并不是所有的硬件平台都能访问任意地址上的任意数据,会直接报错的!
(解释:比如说有的cpu读取4个字节数据,要是没有内存对齐,从1开始那么内存就需要把0-7字节的全部取出来,再剔除掉1/5/6/7,增加了额外的操作,cpu不一定能这么搞,自然就报错了)
性能原因
访问未对齐的内存,需要访问两次;如果对齐的话就只需要一次了。
(解释:比如取int64,按照8个位对齐好了,那获取的话直接就是获取8个字节就好了,边界好判断)
3.如何进行内存对齐?
二个原则:
1.具体类型,对齐值=min(编译器默认对齐值,类型大小Sizeof长度)
2.struct每个字段内部对齐,对齐值=min(默认对齐值,字段最大类型长度)
4.golang的内存对齐如何体现?
4.1 结构体的相同成员不同顺序
结构体是平时写代码经常用到的。相同的成员,不同的排列顺序,会有什么区别吗?
举个例子:
func main()
fmt.Println(unsafe.Sizeof(struct
i8 int8
i16 int16
i32 int32
))
fmt.Println(unsafe.Sizeof(struct
i8 int8
i32 int32
i16 int16
))
输出:
8
12
what?竟然不一样。
分析一波:需要内存对齐的话,因为最大是int32,所以最终记过必须是4个字节的倍数才能对齐。
当8-16-32的时候,类似这样|x-xx|xxxx|。
当8-32-16的时候,类似这样|x—|xxxx|xx–|。
一眼就看出了大小了。
这里的为什么是x-xx而不是xxx-需要说明下。因为当int8放入内存的时候,其占坑1个字节,对齐值为1,而int16占坑2个字节,对齐值为2,所以说会先偏移2个字节从第三个字节才开始放int16的数
4.2指针运算
现在对结构体Test通过指针计算的方式进行赋值。
Test内存情况:|x-xx|xxxx|。需要注意的是这里的“-”需要多计算一个字节才行。
type Test struct
i8 int8
i16 int16
i32 int32
func main()
var t = new(Test)
// 从0开始
var i8 = (*int8)(unsafe.Pointer(t))
*i8 = int8(10)
// 偏移int8+1的字节数,注意这里有个1!!!
var i16 = (*int16)(unsafe.Pointer(uintptr(unsafe.Pointer(t))+ uintptr(1) + uintptr(unsafe.Sizeof(int8(0)))))
*i16 = int16(10)
// 偏移int8+1+int16+的字节数,注意这里有个1!!!
var i32 = (*int32)(unsafe.Pointer(uintptr(unsafe.Pointer(t)) + uintptr(1) + uintptr(unsafe.Sizeof(int8(0))+uintptr(unsafe.Sizeof(int16(0))))))
*i32 = int32(10)
fmt.Println(*t)
输出:
10 10 10
附上两个神器:
功能 | 函数 |
---|---|
获取对齐值 | unsafe.Alignof(t.i16) |
获取偏移值 | unsafe.Offsetof(t.i16) |
5.如何利用内存对齐来优化golang?
5.1 结构体占用内存过大的问题
根据计算对齐值进行成员顺序的拼凑,可以一定程度上缩小结构体占用的内存。
5.2 指针运算的坑
通过分析偏移量和对齐值,准确计算每个成员所偏移的位数,避免算错。
延伸阅读
Go语言实战笔记(二十六)| Go unsafe 包之内存布局
如果你觉得有收获~可以关注我的公众号【咖啡色的羊驼】~第一时间收到我的分享和知识梳理~
以上是关于Golang优化之内存对齐的主要内容,如果未能解决你的问题,请参考以下文章