内存对齐

什么是内存对齐

  • CPU 访问内存时,并不是逐个字节访问,而是以字长(word size)为单位访问,通过内存对齐,减少CPU访问次数,加大CPU访问内存的吞吐量
  • 内存对齐:两个结构体包含的字段类型一致,但是顺序不一致,最终输出的大小也不一样

内存对齐规则

成员对齐规则

  • 针对一个基础类型变量,如果 unsafe.AlignOf() 返回的值是 m,那么该变量的地址需要 被m整除 (如果当前地址不能整除,填充空白字节,直至可以整除

整体对齐规则

  • 针对一个结构体,如果 unsafe.AlignOf() 返回值是 m,需要保证该结构体整体内存占用是 m的整数倍,如果当前不是整数倍,需要在后面填充空白字节。

  • 通过内存对齐后,就可以在保证在访问一个变量地址时:

    1. 如果该变量占用内存小于字长:保证一次访问就能得到数据;
    2. 如果该变量占用内存大于字长:保证第一次内存访问的首地址,是该变量的首地址

空结构体的对齐规则

  • 如果空结构体作为结构体的内置字段:当变量位于结构体的前面和中间时,不会占用内存;当该变量位于结构体的末尾位置时,需要进行内存对齐,内存占用大小和前一个变量的大小保持一致
    type C struct {
    a struct{}
    b int64
    c int64
    }

    type D struct {
    a int64
    b struct{}
    c int64
    }

    type E struct {
    a int64
    b int64
    c struct{}
    }

    type F struct {
    a int32
    b int32
    c struct{}
    }

    func main() {
    fmt.Println(unsafe.Sizeof(C{})) // 16
    fmt.Println(unsafe.Sizeof(D{})) // 16
    fmt.Println(unsafe.Sizeof(E{})) // 24
    fmt.Println(unsafe.Sizeof(F{})) // 12
    }