1 内存管理分析
go语言的变量定义、内存地址一致性似乎是个神秘的问题,例如变量a的地址,&a 每次打印都是一样的地址, 但是多个变量又不一样了?
0xc00000a0c8(不同机器可能不同)
css
a := 43
fmt.Println("a's memory address - ", &a)
你观察到:每次运行都是一样的地址,这其实是 Go 的内存分配优化的一部分。
0xc00000a0c8

- 原因:
逃逸分析 + 栈分配
a 是一个局部变量,如果没有逃逸(即不会被返回或存储到堆中),它就会被分配在 栈上。
markdown
每次程序运行时,Go 会为栈分配一块内存,这块地址很可能是一样的,特别是对于 较小的程序。
编译器优化(静态地址分配)。
css
在某些情况下,Go 编译器会重用内存地址,尤其在简单、重复结构中,为了提升性能,可能为 a 分配在预定义区域。
Go 运行时对堆/栈结构有"启动后固定偏移"的特性。
你可能发现打印出的地址经常是 0xc000xxxxxx 这一类型。这是 Go 的堆起始区域的一种表现。
2 为什么使用其他变量后,变量a 的地址变了
go
b := 42
a := 43
c := 44
fmt.Println(&a)
这时候 a 的地址不再是之前的 0xc00000a0c8,而变成了 0xc0001060b0
- 原因是栈帧结构的不同:
每个函数在运行时会有自己的栈帧(Stack Frame),定义顺序会影响变量在内存中的布局。
当你加入更多变量时,Go 需要重新安排栈空间,这会影响变量的地址。
变量定义顺序影响地址顺序,但不是绝对的(可能被优化器改变):
go
b := 42 // 先分配地址1
a := 43 // 分配地址2
c := 44 // 分配地址3
3 连续变量定义内存中连续分配吗(如 a, b, c)
- 在大多数情况下,Go 会将多个局部变量连续分配在栈上,但不能绝对保证。
Go 编译器可能会重排变量顺序来做内存对齐(比如结构体内的字段顺序优化)。
变量可能会逃逸到堆上,这时地址就不一定连续。
你可以用下面的代码看看它们的整数地址:
perl
fmt.Printf("a: %d\n", &a)
fmt.Printf("b: %d\n", &b)
fmt.Printf("c: %d\n", &c)
如果地址相差是固定的(通常为 8 bytes,因为 int 是 8 字节),说明是在栈上连续分配的。
计算顺序定义的变量是否在内存地址连续差值是否是 8 字节(int 的大小)
css
b := 42
a := 43
c := 44
d := 255
e := 256
f := 355650
fmt.Println("a - ", a)
fmt.Println("a's memory address - ", &a, unsafe.Pointer(&a))
fmt.Printf("%d \n", &a) //整数显示
fmt.Println("b's memory address - ", b, &b, unsafe.Pointer(&b))
fmt.Printf("%d \n", &b) //整数显示
fmt.Println("c's memory address - ", c, &c, unsafe.Pointer(&c))
fmt.Printf("%d \n", &c) //整数显示
fmt.Println("d's memory address - ", d, &d, unsafe.Pointer(&d))
fmt.Printf("%d \n", &d) //整数显示
fmt.Println("e's memory address - ", e, &e, unsafe.Pointer(&e))
fmt.Printf("%d \n", &e) //整数显示
fmt.Println("f's memory address - ", f, &f, unsafe.Pointer(&f))
fmt.Printf("%d \n", &f) //整数显示
运行该小程序,可以得到
css
a - 43
a's memory address - 0xc00000a0e0 0xc00000a0e0
824633762016
b's memory address - 42 0xc00000a0c8 0xc00000a0c8
824633761992
c's memory address - 44 0xc00000a0e8 0xc00000a0e8
824633762024
d's memory address - 255 0xc00000a0f0 0xc00000a0f0
824633762032
e's memory address - 256 0xc00000a0f8 0xc00000a0f8
824633762040
f's memory address - 355650 0xc00000a100 0xc00000a100
824633762048
4 分析结果和原因
可以看到
ini
c - a = 824633762024 - 824633762016 = 8 bytes
a - b = 824633762016 - 824633761992 = 24 bytes
c - b = 824633762024 - 824633761992 = 32 bytes
注意这个差距是 24 字节,不是 8 ------ 这说明 Go 并没有把 a 紧挨着 b 放置。

b 与 a/c 的间隔是 24 字节,不是连续的。这通常可能是由于:
css
变量顺序被优化器重排(Go 并不保证按照你写的顺序分配栈空间);
对齐填充(padding):Go 的栈会尽量保证变量地址按类型对齐,以满足 CPU 的要求(比如 int64 对齐到 8 字节边界);
调试符号或额外保留空间。