检查go语言变量内存结构

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 字节边界);

调试符号或额外保留空间。
相关推荐
uhakadotcom3 分钟前
入门教程:Keras和PyTorch深度学习框架对比
后端·算法·面试
uhakadotcom7 分钟前
Rust 高性能异步 HTTP 库 hyper 入门指南:基础知识与实战示例
后端·面试·github
玛奇玛丶7 分钟前
数据库索引失效了...
后端·mysql
uhakadotcom10 分钟前
消息队列的基本概念入门以及什么是死信策略
后端·面试·github
草捏子17 分钟前
当你在电商下单时,钱到底怎么扣?用TCC模式解决分布式事务难题
后端
奔驰的小野码22 分钟前
本地实现Rtsp视频流推送
java·linux·后端·ffmpeg
这里有鱼汤25 分钟前
无需HTML/CSS!用Python零基础打造专业级数据应用——Streamlit入门指南
前端·后端·python
江湖十年33 分钟前
go-multierror: 更方便的处理你的错误列表
后端·面试·go
谦行1 小时前
前端视角 Java Web 入门手册 5.4:真实世界 Web 开发——Java Web 代码组织与分层
java·后端·架构
Goboy1 小时前
构建异步消息通信机制设计与实现
后端·程序员·架构