11

Go语言之逃逸

 4 years ago
source link: https://studygolang.com/articles/26275
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

转自微信公众号“灰子学技术”,原文链接:https://mp.weixin.qq.com/s/8o8MsExj5BLje38TZoZG5g

本篇做为Go语言内存管理的第一篇文章,会从下面几个方向来讲述:

1.什么是逃逸?
2.为什么需要逃逸?
3.逃逸是怎么实现的?

一、什么是逃逸

在开始讲逃逸之前,我们先看一下,下面的两个例子。

例子1:stack.go的fun()返回的就是一个int变量。

例子2:mem.go的fun()返回的是*int变量,同时里面的返回值是&i。

源代码如下所示:

mE3qaqU.png!web

$ go tool compile -S stack.go //生成汇编语句

mIJRBfI.png!web

汇编结果分析:通过汇编可以看出来,在mem.go中的fun()中的变量i是通过newobject(XX)来生成的数据,这就说明,这个i是存储在对中。

备注:newobject(XX)函数的定义如下所示:

Fzyeeib.png!web

看到上面的例子,有没有觉得很奇怪,为什么mem.go的fun()函数中的i,明明是变量,但是却存储在堆中?

这个其实就是Go语言的 逃逸 ,编译器通过执行静态代码的分析去决定,到底一个变量是应该分配到一个栈上面,还是需要逃逸到一个堆上面。

二、为什么需要逃逸

在分析逃逸之前,我们需要先看下Go语言中的 堆。

在Go语言中,堆作为第二存储位置,Go会优先将数据存在栈里面的。堆是不会自己释放分配的内存的,需要通过GC(garbage collector)也就是垃圾收集器来回收这些分配好的内存。

Go中的栈数据,不能作为指针指向的存储位置。 原因是: goroutine的栈会在栈扩容或者缩减的时候,指向 不同的存储块 。例子如下所示:

zqmERfq.png!web

(摘自:https://play.golang.org/p/pxn5u4EBSI)

一旦指针指向这种栈存储位置,就会在运行的时候出现异常,而Go编译器要想解决这个问题,就会变的更复杂,所以Go的指针就不能指向栈中的存储地址。

想来这个应该也是Go逃逸的数据存储到堆中的原因了。

三、逃逸是怎么实现的

还是以mem.go作为例子,如下所示:

EVFzMnQ.png!web

Output: //./mem

UNfMZnV.png!web

执行$ go build -gcflags "-m -m" mem.go 会得到下面的分析结果:

3UVzQvV.png!web

结果分析:通过输出的结果,我们可以看到line 10的 i, 会根据line 12的return &i来决定,将变量i 分配到堆上面。

逃逸的内存分配如下所示:

1. main函数和fun函数,分别会有两个栈信息,分别为main frame和fun frame,如下图所示。

2.在fun frame中,变量i会在heap中分配对应的数据,地址为0xc000014080,变量值此时为0。

3.main函数在调用fun()之后,会copy一份i的值给变量a,此时的a的地址是0xc0000c028,存的值是i的地址0xc000014080,这个地址在堆中。

4.不管是在fun还是在main函数中,操作地址0xc000014080就可以取到对应的数值。

viURfiZ.png!web

参考资料:

Language Mechanics On Escape Analysis:https://www.ardanlabs.com/blog/2017/05/language-mechanics-on-escape-analysis.html

Go's Memory Allocator - Overview:https://andrestc.com/post/go-memory-allocation-pt1/

灰子学技术:

Yzaiyy6.jpg!web


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK