【Go专家编程——内存管理——逃逸分析】

逃逸分析

逃逸分析(Escape Analysis)是指由编译器决定内存分配的位置,不需要程序员决定。

  • 在函数中申请一个新的对象
    • 如果分配在栈上,则函数执行结束后可自动将内存回收
    • 如果分配在堆上,则函数执行结束后可交给GC(垃圾回收)处理
  • 有了逃逸分析,返回函数局部变量变得可能
  • 逃逸分析还跟闭包息息相关

1.逃逸策略

在函数中申请新对象时,编译器会根据该对象是否被函数外部引用来决定是否逃逸:

  • 如果函数外部没有引用,则优先放到栈中
  • 如果函数外部存在引用,则必定放到堆中
  • 注意点:对于仅在函数内部使用的变量,也有可能放入堆中,如内存过大超过栈的存储能力。

2. 逃逸场景

我们可以通过编译参数-gcflags=-m来查看编译过程中的逃逸分析过程

例如go build -gcflags=-m

2.1 指针逃逸

go 复制代码
type Student struct {
	Name string
	Age int
}

func StudentRegister(name string,age int) *Student{
	s := new(Student)	// 局部变量s逃逸到堆中
	s.Name = name
	s.Age = age
	return s
}
func main(){
	StudentRegister("Jim", 18)
}

函数StudentRegister()内部的s为局部变量,其值通过函数返回值返回,s本身为一个指针,其指向的内存地址不会是栈而是堆。

2.2 栈空间不足逃逸

go 复制代码
func Slice(){
	s := make([]int,1000,1000)
	for index,_ := range s{
		s[index] = index
	}
}
func main(){
	Slice()
}

Slice函数分配了一个长度为1000的切片,是否逃逸取决于栈的空间是否足够大。

当切片长度不断增加到10000时就会发生逃逸

  • 实际上当栈的空间不足以存放当前对象或无法判断当前切片长度时会将对象分配到堆中

2.3 动态类型逃逸

很多函数的参数为interface类型,比如fmt.Println(a ...interface{}),编译期间很难确定其参数具体类型,也会产生逃逸。

go 复制代码
func main(){
	s := "Escape"
	fmt.Println(s) 
}

2.4 闭包引用对象逃逸

go 复制代码
func Fibonacci() func() int {
	a,b := 0,1
	return func() int {
		a, b = b,a+b
		return a
	}
}

func main(){
	f := Fibonacci()
	for i:=0;i<10;i++{
		fmt.Printf("Fibonacci: %d\n",f())
	}
}

该函数返回一个闭包,闭包使用了函数的局部变量a,b,使用时通过该函数获取闭包,然后每次执行闭包都会一次输出Fibonacci数列。

Fibonacci()函数中原本属于局部变量的a和b由于闭包的引用,不得不将两者放到堆上,以至于产生了逃逸。

3. 小结

  • 栈上分配内存比在堆上分配内存有更高的效率
  • 栈上分配的内存不需要GC处理
  • 堆上分配的内存使用完毕会交给GC处理
  • 逃逸分析的目的是决定分配地址是栈还是堆
  • 逃逸分析在编译阶段完成
相关推荐
时间的拾荒人30 分钟前
Qt 文件操作详解:从基础类到读写实战
开发语言·qt·面试
Wang's Blog40 分钟前
Java 项目实战: 外卖平台优化-YApi接口管理平台与文档导入导出
java·开发语言·yapi
专业程序开发源1 小时前
django新闻推荐系统70655-计算机课程设计、毕业设计
java·javascript·spring boot·后端·python·django·课程设计
jimy11 小时前
基类没有虚析构函数,基类指针删除派生类对象,行为是未定义的
开发语言·c++
迅猛龙办公室1 小时前
python获取星期字符串
开发语言·python
打工仔折腾 AI1 小时前
把 AI Agent 托管到家里电脑:UU远程端口映射与CLI实测记录
人工智能·后端·python·langchain·电脑·ai agent 实战
vx_Biye_Design1 小时前
springboot一站式旅游管理平台81037-计算机课程设计、毕业设计
java·vue.js·spring boot·后端·课程设计·express·旅游
嵌入式学习菌1 小时前
ESP32 ModbusTCP 分片缓存
java·后端·spring
程序员小杰@1 小时前
Spring Boot 常用注解分类速记
java·spring boot·后端
挖掘狂人1 小时前
Git 从 0 到 1:用一个小项目走完 add / commit / reset / merge / rebase / push
git·后端·github