如何理解Go语言中的逃逸
这篇文章给大家介绍如何理解Go语言中的逃逸,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。
创新互联公司专注于企业网络营销推广、网站重做改版、安多网站定制设计、自适应品牌网站建设、H5页面制作、商城网站建设、集团公司官网建设、外贸网站建设、高端网站制作、响应式网页设计等建站业务,价格优惠性价比高,为安多等各大城市提供网站开发制作服务。
一、什么是逃逸
在开始讲逃逸之前,我们先看一下,下面的两个例子。
例子1:stack.go的fun()返回的就是一个int变量。
例子2:mem.go的fun()返回的是*int变量,同时里面的返回值是&i。
源代码如下所示:
$ go tool compile -S stack.go //生成汇编语句
汇编结果分析:通过汇编可以看出来,在mem.go中的fun()中的变量i是通过newobject(XX)来生成的数据,这就说明,这个i是存储在对中。
备注:newobject(XX)函数的定义如下所示:
看到上面的例子,有没有觉得很奇怪,为什么mem.go的fun()函数中的i,明明是变量,但是却存储在堆中?
这个其实就是Go语言的逃逸,编译器通过执行静态代码的分析去决定,到底一个变量是应该分配到一个栈上面,还是需要逃逸到一个堆上面。
二、为什么需要逃逸
在分析逃逸之前,我们需要先看下Go语言中的堆。
在Go语言中,堆作为第二存储位置,Go会优先将数据存在栈里面的。堆是不会自己释放分配的内存的,需要通过GC(garbage collector)也就是垃圾收集器来回收这些分配好的内存。
Go中的栈数据,不能作为指针指向的存储位置。原因是:goroutine的栈会在栈扩容或者缩减的时候,指向不同的存储块。例子如下所示:
(摘自:https://play.golang.org/p/pxn5u4EBSI)
一旦指针指向这种栈存储位置,就会在运行的时候出现异常,而Go编译器要想解决这个问题,就会变的更复杂,所以Go的指针就不能指向栈中的存储地址。
想来这个应该也是Go逃逸的数据存储到堆中的原因了。
三、逃逸是怎么实现的
还是以mem.go作为例子,如下所示:
Output: //./mem
执行$ go build -gcflags "-m -m" mem.go 会得到下面的分析结果:
结果分析:通过输出的结果,我们可以看到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就可以取到对应的数值。
关于如何理解Go语言中的逃逸就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。
文章名称:如何理解Go语言中的逃逸
网页网址:http://myzitong.com/article/gpsghe.html