go语言之内存对齐

之所以要了解内存对齐,本质也是为了提高程序运行效率,也是为了更好地优化内存

对齐系数

go语言之内存对齐_第1张图片

对齐系数就是为了确定变量的内存地址的,内存地址必须得是对齐系数的整倍数

go语言之内存对齐_第2张图片

这里面我们看下基本类型的对齐系数都是多少:

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

结构体对齐

结构体对齐需要考虑两部分,一部分是结构体的内部对齐,也就是要考虑结构体的成员大小和成员的对齐系数,另一部分就是结构体长度填充,考虑系统字长

go语言之内存对齐_第3张图片

go语言之内存对齐_第4张图片

go语言之内存对齐_第5张图片

go语言之内存对齐_第6张图片

在这里结构体最大成员长度就是string这个成员的长度是16个字节,系统字长8个字节(64位),所以结构体的长度就需要是min(16,8)=8的整数倍。因此你会看到下图中的补齐0的部分。

go语言之内存对齐_第7张图片

go语言之内存对齐_第8张图片

其实我们针对上述结构体的定义,我们看到bool之后和string之间其实浪费了大量的空间,那么我们可以通过调整顺序进行优化,将c init16定义在b string之前,就可以节约空间。节省空间如下所示:

go语言之内存对齐_第9张图片

go语言之内存对齐_第10张图片

围绕着上述的问题:

首先string的对齐系数为什么是8, 因为string本身是结构体,里面一个指针,一个int的len,它的对齐系数其实就是string结构体最大成员的对齐系数,就是8

刚才的DEMO结构体对齐系数就是max(1, 8, 2) = 8

结构体对齐之特殊点:空结构体对齐

go语言之内存对齐_第11张图片

go语言之内存对齐_第12张图片

内存对齐总结

go语言之内存对齐_第13张图片

你可能感兴趣的:(Go语言,go语言,go)