返回归档
🧮Golang

内存对齐

文章目录

为什么要内存对齐

  • 平台原因:各个硬件平台对存储空间的处理上有很大的不同。一些平台对某些特定类型的数据只能从某些特定地址开始存取。比如,有些架构的CPU在访问一个没有进行对齐的变量的时候会发生错误,那么在这种架构下编程必须保证字节对齐。
  • 性能原因:内存对齐可以提高存取效率。比如,有些平台每次读都是从偶地址开始,如果一个int型(假设为32位系统)如果存放在偶地址开始的地方,那么一个读周期就可以读出这32bit,而如果存放在奇地址开始的地方,就需要2个读周期,并对两次读出的结果的高低字节进行拼凑才能得到该32bit数据。

对齐的规则

  1. 数据成员对⻬规则:结构(struct)(或联合(union))的数据成员,第⼀个数据成员放在offset为0的地⽅以后每个数据成员存储的起始位置要从该成员⼤⼩或者成员的⼦成员⼤⼩(只要该成员有⼦成员,⽐如说是数组,结构体等)的整数倍开始(⽐如int为4字节,则要从4的整数倍地址开始存储。
  2. **结构体作为成员:如果⼀个结构⾥有某些结构体成员,则结构体成员要从其内部最⼤元素⼤⼩的整数倍**地址开始存储.(比如:struct a⾥存有struct b, b⾥有char,int ,double等元素,那b应该从8的整数倍开始存储.)
  3. 结构体的总⼤⼩,也就是sizeof的结果,必须是其内部最⼤成员的整数倍.不⾜的要补⻬****。
  4. 结构体的总⼤⼩,也就是sizeof的结果,必须是其内部最⼤成员的整数倍.不⾜的要补⻬****。

示例

package main

import (
	"fmt"
	"unsafe"
)

type MyStruct struct {
	//a int
	b int32
	//c int16
	d byte
	e int16
	f byte
	g byte
	h byte
}

func main() {
	//println(unsafe.Sizeof(int(1)))
	//println(unsafe.Sizeof(int32(1)))
	//println(unsafe.Sizeof(int16(1)))
	//println(unsafe.Sizeof(byte(1)))

	println("-------------------------")

	s := MyStruct{}
	println(unsafe.Sizeof(s))
	//fmt.Printf("Offset of a: %d\n", unsafe.Offsetof(s.a))
	//fmt.Printf("Offset of b: %d\n", unsafe.Offsetof(s.b))
	//fmt.Printf("Offset of c: %d\n", unsafe.Offsetof(s.c))
	//fmt.Printf("Offset of d: %d\n", unsafe.Offsetof(s.d))
	//fmt.Printf("Offset of e: %d\n", unsafe.Offsetof(s.e))
	//fmt.Printf("Offset of f: %d\n", unsafe.Offsetof(s.f))
	//fmt.Printf("Offset of g: %d\n", unsafe.Offsetof(s.g))
	fmt.Printf("Offset of h: %d\n", unsafe.Offsetof(s.h))
}

ref