之所以要了解内存对齐,本质也是为了提高程序运行效率,也是为了更好地优化内存
对齐系数就是为了确定变量的内存地址的,内存地址必须得是对齐系数的整倍数
这里面我们看下基本类型的对齐系数都是多少:
package main
import (
"fmt"
"unsafe"
)
func main() {
fmt.Printf("bool 长度: %d, 内存系数: %d\n", unsafe.Sizeof(bool(true)), unsafe.Alignof(bool(true)))
fmt.Printf("byte 长度: %d, 内存系数: %d\n", unsafe.Sizeof(byte(0)), unsafe.Alignof(byte(0)))
fmt.Printf("int 长度: %d, 内存系数: %d\n", unsafe.Sizeof(int(0)), unsafe.Alignof(int(0)))
fmt.Printf("int8 长度: %d, 内存系数: %d\n", unsafe.Sizeof(int8(0)), unsafe.Alignof(int8(0)))
fmt.Printf("int16 长度: %d, 内存系数: %d\n", unsafe.Sizeof(int16(0)), unsafe.Alignof(int16(0)))
fmt.Printf("int32 长度: %d, 内存系数: %d\n", unsafe.Sizeof(int32(0)), unsafe.Alignof(int32(0)))
fmt.Printf("int64 长度: %d, 内存系数: %d\n", unsafe.Sizeof(int64(0)), unsafe.Alignof(int64(0)))
fmt.Printf("string 长度: %d, 内存系数: %d\n", unsafe.Sizeof("abc"), unsafe.Alignof("abc"))
fmt.Printf("float32 长度: %d, 内存系数: %d\n", unsafe.Sizeof(float32(1.0)), unsafe.Alignof(float32(1.0)))
fmt.Printf("float64 长度: %d, 内存系数: %d\n", unsafe.Sizeof(float64(1.0)), unsafe.Alignof(float64(1.0)))
i := 10.0
fmt.Printf("指针 长度: %d, 内存系数: %d\n", unsafe.Sizeof(&i), unsafe.Alignof(&i))
ii := map[string]int{"a": 1}
fmt.Printf("指针 长度: %d, 内存系数: %d\n", unsafe.Sizeof(&ii), unsafe.Alignof(&ii))
}
结果输出:
go run memaddrdemo.go
bool 长度: 1, 内存系数: 1
byte 长度: 1, 内存系数: 1
int 长度: 8, 内存系数: 8
int8 长度: 1, 内存系数: 1
int16 长度: 2, 内存系数: 2
int32 长度: 4, 内存系数: 4
int64 长度: 8, 内存系数: 8
string 长度: 16, 内存系数: 8
float32 长度: 4, 内存系数: 4
float64 长度: 8, 内存系数: 8
指针 长度: 8, 内存系数: 8
指针 长度: 8, 内存系数: 8
这里面我们重点关注一下为什么string的内存系数是8,长度是16
string底层是一个结构体,通过反射我们看下它的组成部分:
type StringHeader struct {
Data uintptr
Len int
}
它主要有两部分组成:1 是指针,二是Len
指针的长度是8,int的长度在64位机器也是8,那么其长度就是16.但是结构体的对齐系数下面会详细去讲,是结构体成员最大对齐系数,那么就是max(8,8) = 8,所以string的对齐系数是8,但是长度是16
结构体对齐需要考虑两部分,一部分是结构体的内部对齐,也就是要考虑结构体的成员大小和成员的对齐系数,另一部分就是结构体长度填充,考虑系统字长
在这里结构体最大成员长度就是string这个成员的长度是16个字节,系统字长8个字节(64位),所以结构体的长度就需要是min(16,8)=8的整数倍。因此你会看到下图中的补齐0的部分。
其实我们针对上述结构体的定义,我们看到bool之后和string之间其实浪费了大量的空间,那么我们可以通过调整顺序进行优化,将c init16定义在b string之前,就可以节约空间。节省空间如下所示:
围绕着上述的问题:
首先string的对齐系数为什么是8, 因为string本身是结构体,里面一个指针,一个int的len,它的对齐系数其实就是string结构体最大成员的对齐系数,就是8
刚才的DEMO结构体对齐系数就是max(1, 8, 2) = 8