文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

golang内存对齐的概念及案例详解

2024-04-02 19:55

关注

什么是内存对齐

为保证程序顺利高效的运行,编译器会把各种类型的数据安排到合适的地址,并占用合适的长度,这就是内存对齐。

每种类型的对齐值就是它的对齐边界,内存对齐要求数据存储地址以及占用的字节数都要是它的对齐边界的倍数。所以下述的int32要错开两个字节,从4开始存,却不能紧接着从2开始。

也可以这样解释:

CPU把内存当成是一块一块的,块的大小可以是2,4,8,16字节大小,因此CPU在读取内存时是一块一块进行读取的。块大小成为memory access granularity(粒度)。

如果不进行内存对齐

比如我们想从地址1开始读8字节的数据:

CPU会分两次读:

分两次读,这样势必会对性能造成影响。

为什么要内存对齐

原因主要有两点:

对齐边界

那该怎么确定每种数据的对齐边界呢?这和平台有关,go语言支持这些平台:

可以看到常见的32位平台,指针宽度和寄存器宽度都是4字节,64位平台上都是8字节。而被go语言称为寄存器宽度的这个值,就可以理解为机器字长,也是平台对应的最大对齐边界。

而数据类型的对齐边界,是取类型大小与平台最大对齐边界中较小的那个。不过要注意,同一个类型在不同平台上,大小可能不同,对齐边界也可能不同。

为什么不统一使用平台最大对齐边界呢?或者统一按各类型大小来对齐呢?

我们来试一下,假设目前是64位平台,最大对齐边界为8字节。int8只有1字节,按照1字节对齐的话,它可以放在任何位置,因为总能通过一次读取把它完整拿出来。如果统一对齐到8字节,虽然同样只要读取一次,但每个int8的变量都要浪费7字节,所以对齐到1。

int16占2字节,按照2字节对齐,可以从这些地址开始存,而且能保证只用读取一次。

如果按1字节对齐就可能存成这样,那就要读取两次再截取拼接,会影响性能。

如果按8字节对齐,会与int8一样浪费内存,所以对齐到2。

这是小于最大对齐边界的情况,再来看看大于的情况。

假设要在32位的平台下存储一个int64类型的数据,在0和1位置被占用的情况下,就要从位置8开始存。而如果对齐到4,就可以从位置4开始,内存浪费更少,所以选择对齐到4。

因此类型对齐边界会这样选择,依然是为了减少浪费提升性能。

GO 计算对齐边界函数

在go语言中可以调用 unsafe.Alignof 来返回相应类型的对齐边界:

func main() {
	fmt.Printf("bool align: %d\n", unsafe.Alignof(bool(true)))
	fmt.Printf("int32 align: %d\n", unsafe.Alignof(int32(0)))
	fmt.Printf("int8 align: %d\n", unsafe.Alignof(int8(0)))
	fmt.Printf("int64 align: %d\n", unsafe.Alignof(int64(0)))
	fmt.Printf("byte align: %d\n", unsafe.Alignof(byte(0)))
	fmt.Printf("string align: %d\n", unsafe.Alignof("EDDYCJY"))
	fmt.Printf("map align: %d\n", unsafe.Alignof(map[string]string{}))
}

运行结果:

bool align: 1
int32 align: 4
int8 align: 1
int64 align: 8
byte align: 1
string align: 8
map align: 8

确定结构体的对齐边界

对结构体而言,首先要确定每个成员的对齐边界,然后取其中最大的,这就是这个结构体的对齐边界。

然后来存储这个结构体变量:

内存对齐要求一:

​假设从0开始存,结构体的每个成员在存储时,都要把这个起始地址当作地址0,然后再用相对地址来决定自己该放在哪里。

内存对齐要求2:

​所以最终上述结构体类型的大小就是24字节。

案例

type Part1 struct {
	a bool
	b int32
	c int8
	d int64
	e byte
}
type Part2 struct {
	a bool
	c int8
	e byte
	b int32 // 4个字节
	d int64
}

分别求以上两个结构体占用的字节:

fmt.Printf("part1 size: %d, align: %d\n", unsafe.Sizeof(part1), unsafe.Alignof(part1))
fmt.Printf("part2 size: %d, align: %d\n", unsafe.Sizeof(part2), unsafe.Alignof(part2))

这里我们直接调用函数求得:

part1 size: 32, align: 8
part2 size: 16, align: 8

原因请读者来思考。

参考资料:
https://blog.csdn.net/u010853261/article/details/102557188
https://www.bilibili.com/video/BV1Ja4y1i7AF?from=search&seid=16213689667007976568&spm_id_from=333.337.0.0

到此这篇关于golang内存对齐的文章就介绍到这了,更多相关golang内存对齐内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯