go语言学习笔记 — 基础 — 基本语法 — 常量与变量 — 变量的生命周期:变量逃逸分析 —— go编译器自动决定变量的内存分配方式(堆还是栈),提高程序运行效率
Posted Locutus
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了go语言学习笔记 — 基础 — 基本语法 — 常量与变量 — 变量的生命周期:变量逃逸分析 —— go编译器自动决定变量的内存分配方式(堆还是栈),提高程序运行效率相关的知识,希望对你有一定的参考价值。
C/C++语言需要开发者自己管理内存分配,选择合适的内存分配方式以适应不同算法需求:函数的局部变量尽量使用栈内存分配;全局变量、结构体成员变量使用堆内存分配等。
变量逃逸分析:go语言把内存分配的过程整合到编译器中,由go编译器分析代码的特征和生命周期,自动选择堆分配内存还是栈分配内存。上述过程对程序员是透明的,不会感知,不需要耗费精力。编译器决定选择堆分配还是栈分配的原则。
- 变量是否发生逃逸
- 变量是否被取地址
变量逃逸分析(使用哪种内存分配机制)
package main
import (
"fmt"
)
// 测试函数入参和返回值
func dummy(a int) int {
var b int // 声明局部变量(临时变量)
b = a
return b // 返回临时变量
}
// 空函数,没有任何入参和返回值
func void() {}
func main() {
var c int // 测试在main函数中的变量分析
void()
fmt.Println(c, dummy(0))
}
// -gcflags是编译参数,-m表示进行对内存分配分析,-l表示避免程序内联优化
# go run -gcflags "-m -l" var_escape.go
./var_escape.go:21:13: c escapes to heap
./var_escape.go:21:22: dummy(0) escapes to heap
./var_escape.go:21:13: main ... argument does not escape
0 0
b是整型,通过函数dummy()返回,逃出了dummy()函数(dummy(0) escapes to heap);使用堆heap分配,给变量c分配内存。
取变量的内存地址时,进行变量逃逸分析
package main
import "fmt"
// 空结构体
type data struct{}
func dummy() *data {
var c data // 声明c为data结构体类型,基本的实例化,是值类型
return &c // 返回函数局部变量的内存地址,是*data类型指针
}
func main() {
fmt.Println(dummy()) //打印dummy函数的返回值
}
# go run -gc flags "-m -l" addrs_escape.go
#command-line-arguments
./addrs_escape.go:11:9: &c escapes to heap
./addrs_escape.go:9:6: moved to heap: c
./addrs_escape.go:15:19: dummy() escapes to heap
./addrs_escape.go:15:13: main ... argument does not escape
&{}
把c移到heap堆中。go最终选择把c的data结构分配到堆上,然后由GC去回收c的内存。
以上是关于go语言学习笔记 — 基础 — 基本语法 — 常量与变量 — 变量的生命周期:变量逃逸分析 —— go编译器自动决定变量的内存分配方式(堆还是栈),提高程序运行效率的主要内容,如果未能解决你的问题,请参考以下文章
go语言学习笔记 — 基础 — 基本语法 — 常量与变量 — 常量变量的声明:单个变量的声明与赋值
go语言学习笔记 — 基础 — 基本语法 — 常量与变量 — 变量的数值类型转换
go语言学习笔记 — 基础 — 基本语法 — 常量与变量 — 常量变量的声明:变量初始化声明和变量赋值
go语言学习笔记 — 基础 — 基本语法 — 常量与变量 — 常量变量的声明:多个变量的初始化声明与赋值