go 内存对齐

Posted jun10ng

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了go 内存对齐相关的知识,希望对你有一定的参考价值。

go 内存对齐

前言

学过操作系统的人知道,OS为了CPU读取方便会一次性读取一块的单位,这个块的开大小又称为内存访问粒度

在64位系统中,这个粒度为8,也就是一次性读取8个字节。

unsafe.Sizeof()  //返回传入参数的大小
unsafe.Alignof() //返回对齐参数

对齐规则

  1. 结构体的成员变量,第一个成员变量的偏移量为 0。往后的每个成员变量的对齐值必须为编译器默认对齐长度#pragma pack(n))或当前成员变量类型的长度unsafe.Sizeof),取最小值作为当前类型的对齐值。其偏移量必须为对齐值的整数倍

  2. 结构体本身,对齐值必须为8的最小整数倍

结合以上两点,可得知若编译器默认对齐长度#pragma pack(n))超过结构体内成员变量的类型最大长度时,默认对齐长度是没有任何意义的

操作

我们先来看下两个结构体,他们的成员是相同的,但是排列顺序不一样。这些成员的大小加起来都是15字节。

type q1 struct {
	a bool   //1
	b int32   //4
	c int8   //1
	d int64  //8
	e byte   //1
}

type q2 struct {
	e byte  //1
	c int8  //1
	a bool  //1
	b int32 //4
	d int64  //8
}

现在,我们输出这两个结构体的大小,他们会一样吗?

	q1 := q1{}
	q2 := q2{}

	fmt.Printf("q1 size :%d,align:%d
",unsafe.Sizeof(q1),unsafe.Alignof(q1))
	fmt.Printf("q2 size :%d,align:%d
",unsafe.Sizeof(q2),unsafe.Alignof(q2))

	//output
//	q1 size :32,align:8
//	q2 size :16,align:8

差异很大,这个差异就是由于内存对齐导致的。接下来,我们来看下这个差异如何构成的。

q1在内存中的排列如下,-符号代表因内存对齐而浪费的字节。

a---bbbc---dddddddde---   共计32个字节

q2在内存中排列如下:

abc-bbbdddddddd 共计16字节

以上是关于go 内存对齐的主要内容,如果未能解决你的问题,请参考以下文章

Go 内存对齐的那些事儿

Go | 结构体及内存对齐

按位或运算符 | C中用于对齐内存块的用法[重复]

内存对齐问题

Go中的地址对齐

GLSL 结构数组 - 内存分配/对齐