持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第2天,点击查看活动详情
1、常见的逃逸现象
编译器根据代码的特征和生命周期,自动的把变量分配到堆或者是栈上面。在编译阶段才能确认逃逸,人不是在运行时。
1、返回函数类型逃逸
1、返回一个函数类型的时候就会发生逃逸。
package main
import "fmt"
func main() {
test := testfunc()
fmt.Println(name())
}
//testfunc 返回一个 func()string{} 匿名函数
func testfunc() func() string {
// func()返回一个string类型
return func() string {
return "函数逃逸"
}
}
控制台输入命令:
//-m为内存分析 -l防止内联优化
go build -gcflags="-m -l" funcType.go //funcType为文件名
返回结果:
很显然,name() 逃逸到了堆里
2、在方法内把局部变量指针返回
package main
import "fmt"
//定义一个结构体
type X struct {
s string
}
//
func foo(s string) *X {
x := new(X)
x.s = s
return x //返回局部变量x,在C语言中属于是野指针,会报错,但在go则不报错,但a会逃逸到堆
}
func main() {
//将函数的返回的*X赋值给a
a := foo("逃")
//字符串拼接
b := a.s + "逸"
c := b + "了!"
fmt.Println(c)
}
//运行结果:
逃逸了!
控制台输入命令 输出结果:
结果分析: new(x)逃逸到了堆
b+"了" 逃逸···
3、除了这两个行为会发生逃逸现象以外,还有很多。
比如: 1、发送指针或带有指针的值到 channel 中。
2、在一个切片上存储指针或带指针的值。
3、slice 的背后数组被重新分配了(超出容量)
4、channel 或者栈空间不足逃逸
4、堆和栈
简单来说:栈( stack)是系统自动分配空间的,堆是由程序员自己申请的
栈在内存中是从高地址向下分配的,并且连续的,遵循先进后出原则。(存数据相当于砌墙,检索数据相当于拆墙。)
堆分配是从低地址向高地址分配的,每次分配的内存大小可能不一致,导致了空间是不连续的,这也产生内存碎片的原因。所以速度就会更慢。