go-内存对齐

本文提纲

  • go内存对齐介绍
  • go内存对齐场景

go内存对齐介绍

为什么需要内存对齐

将内存对齐数据总线的宽度,降低硬件实现复杂度,提升传输的效率。

go内存对齐规则

go内存对齐主要参考因素:

  • 数据类型自身的大小,符合类型会参考最大成员的大小
  • 硬件平台的机器字长

go内存对齐的规则:

  • 起始地址 必须是对齐边界的整数倍
  • 结构体整体占用字节数 必须是内存对齐边界的整数倍

可以用个unsafe.Sizeof()获取自身类型大小,可以用unsafe.Alignof()获取内存对齐编辑。

go常见内置类型的大小和对齐边界

在这里插入图片描述

go内存对齐场景及举例

go常见的内存对齐场景主要是struct和函数的返参和入参。
函数内的局部变量也会内存对齐,不过会自动优化,不需要额外考虑。

struct

未优化前结构体s1如下:

type s1 struct {
 a int8
 b int64
 c int8
 d int32
 e int16
}

未优化前结构体s1内存对齐后布局如下:
在这里插入图片描述

内存对齐优化后结构体S2:

type s2 struct {
	a int8
	c int8
	e int16
	d int32
	b int64
}

在这里插入图片描述

函数返回参数和入参

go函数的返参和入参内存布局等价于结构体。

  • go函数的返参和入参的入栈顺序是先返参后入参,并且都是从右往左。
    具体参数入栈等后续函数栈帧出再介绍。
  • 调用函数时,参数和返回值看起来更像是先参数后返回值,从左至右的顺序分配,并且是从低地址开始使用的。

函数内局部变量

函数内的局部变量也等价于结构体,但是局部变量在栈帧上会顺序调整,与声明顺序并不一定一致。
举例:

func f() {
	var a int8
	var b int64
	var c int32
	var d int16
	var e int8
	println(&a, &b, &c, &d, &e)
}

输出结果:

0x88387b1 0x88387b8 0x88387b4 0x88387b2 0x88387b0

等价于结构体布局:

type sf struct {
	e int8
	a int8
	d int16
	c int32
	b int64
}

为什么go编译器会优化局部变量内存布局,而不优化参数和返回值的内存布局呢?

因为函数本身是对代码单元的封装,参数和返回值属于对外暴露的接口,编译器必须按照函数原型来呈现,而局部变量属于封装在内部的参数,不会对外暴露,所以编译器可以优化调整布局,不会对函数意外造成影响。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值