聊聊Golang逃逸分析

逃逸分析的概念,go怎么开启逃逸分析的log。 以下资料来自互联网,有错误之处,请一定告之。
什么是逃逸分析
wiki上的定义
在编译程序优化理论中,逃逸分析是一种确定指针动态范围的方法——分析在程序的哪些地方可以访问到指针。它涉及到指针分析和形状分析。
当一个变量(或对象)在子程序中被分配时,一个指向变量的指针可能逃逸到其它执行线程中,或是返回到调用者子程序。如果使用尾递归优化(通常在函数编程语言中是需要的),对象也可以看作逃逸到被调用的子程序中。如果一种语言支持第一类型的延续性在Scheme和Standard ML of New Jersey中同样如此),部分调用栈也可能发生逃逸。
如果一个子程序分配一个对象并返回一个该对象的指针,该对象可能在程序中被访问到的地方无法确定——这样指针就成功“逃逸”了。如果指针存储在全局变量或者其它数据结构中,因为全局变量是可以在当前子程序之外访问的,此时指针也发生了逃逸。
逃逸分析确定某个指针可以存储的所有地方,以及确定能否保证指针的生命周期只在当前进程或线程中。
逃逸分析的用处(为了性能)
- 最大的好处应该是减少gc的压力,不逃逸的对象分配在栈上,当函数返回时就回收了资源,不需要gc标记清除。
- 因为逃逸分析完后可以确定哪些变量可以分配在栈上,栈的分配比堆快,性能好
- 同步消除,如果你定义的对象的方法上有同步锁,但在运行时,却只有一个线程在访问,此时逃逸分析后的机器码,会去掉同步锁运行。
go消除了堆和栈的区别
go在一定程度消除了堆和栈的区别,因为go在编译的时候进行逃逸分析,来决定一个对象放栈上还是放堆上,不逃逸的对象放栈上,可能逃逸的放堆上。
开启go编译时的逃逸分析日志
开启逃逸分析日志很简单,只要在编译的时候加上-gcflags '-m',但是我们为了不让编译时自动内连函数,一般会加-l参数,最终为-gcflags '-m -l'
Example:
package main
import (
"fmt"
)
func main() {
s := "hello"
fmt.Println(s)
}
go run -gcflags '-m -l' escape.go Output:
# command-line-arguments
escape_analysis/main.go:9: s escapes to heap
escape_analysis/main.go:9: main ... argument does not escape
hello
什么时候逃逸,什么时候不逃逸
Example1:
package main
type S struct{}
func main() {
var x S
y := &x
_ = *identity(y)
}
func identity(z *S) *S {
return z
}
Output:
# command-line-arguments
escape_analysis/main.go:11: leaking param: z to result ~r1 level=0
escape_analysis/main.go:7: main &x does not escape
这里的第一行表示z变量是“流式”,因为identity这个函数仅仅输入一个变量,又将这个变量作为返回输出,但identity并没有引用z,所以这个变量没有逃逸,而x没有被引用,且生命周期也在mian里,x没有逃逸,分配在栈上。
Example2:
package main
type S struct{}
func main() {
var x S
_ = *ref(x)
}
func ref(z S) *S {
return &z
}
Output:
# command-line-arguments
escape_analysis/main.go:11: &z escapes to heap
escape_analysis/main.go:10: moved to heap: z
这里的z是逃逸了,原因很简单,go都是值传递,ref函数copy了x的值,传给z,返回z的指针,然后在函数外被引用,说明z这个变量在函数內声明,可能会被函数外的其他程序访问。所以z逃逸了,分配在堆上
对象里的变量会怎么样呢?看下面
Example3:
package main
type S struct {
M *int
}
func main() {
var i int
refStruct(i)
}
func refStruct(y int) (z S) {
z.M = &y
return z
}
Output:
# command-line-arguments
escape_analysis/main.go:13: &y escapes to heap
escape_analysis/main.go:12: moved to heap: y
看日志的输出,这里的y是逃逸了,看来在struct里好像并没有区别,有可能被函数外的程序访问就会逃逸
Example4:
package main
type S struct {
M *int
}
func main() {
var i int
refStruct(&i)
}
func refStruct(y *int) (z S) {
z.M = y
return z
}
Output:
# command-line-arguments
escape_analysis/main.go:12: leaking param: y to result z level=0
escape_analysis/main.go:9: main &i does not escape
这里的y没有逃逸,分配在栈上,原因和Example1是一样的。
Example5:
package main
type S struct {
M *int
}
func main() {
var x S
var i int
ref(&i, &x)
}
func ref(y *int, z *S) {
z.M = y
}
Output:
# command-line-arguments
escape_analysis/main.go:13: leaking param: y
escape_analysis/main.go:13: ref z does not escape
escape_analysis/main.go:10: &i escapes to heap
escape_analysis/main.go:9: moved to heap: i
escape_analysis/main.go:10: main &x does not escape
这里的z没有逃逸,而i却逃逸了,这是因为go的逃逸分析不知道z和i的关系,逃逸分析不知道参数y是z的一个成员,所以只能把它分配给堆。
参考
Go Escape Analysis Flaws go-escape-analysis
聊聊Golang逃逸分析的更多相关文章
- Golang逃逸分析
Golang逃逸分析 介绍逃逸分析的概念,go怎么开启逃逸分析的log. 以下资料来自互联网,有错误之处,请一定告之. sheepbao 2017.06.10 什么是逃逸分析 wiki上的定义 In ...
- golang逃逸分析和竞争检测
最近在线上发现一块代码逻辑在执行N次耗时波动很大1ms~800ms,最开始以为是gc的问题,对代码进行逃逸分析,看哪些变量被分配到堆上了,后来发现是并发编程时对一个切片并发的写,导致存在竞争,类似下面 ...
- 逃逸分析与栈、堆分配分析 escape_analysis
小结: 1.当形参为 interface 类型时,在编译阶段编译器无法确定其具体的类型.因此会产生逃逸,最终分配到堆上. 2.The construction of a value doesn't d ...
- 基于Golang的逃逸分析(Language Mechanics On Escape Analysis)
何为逃逸分析 在编译程序优化理论中,逃逸分析是一种确定指针动态范围的方法——分析在程序的哪些地方可以访问到指针.它涉及到指针分析和形状分析. 当一个变量(或对象)在子程序中被分配时,一个指向变量的指针 ...
- Go变量逃逸分析
目录 什么是逃逸分析 为什么要逃逸分析 逃逸分析是怎么完成的 逃逸分析实例 总结 写过C/C++的同学都知道,调用著名的malloc和new函数可以在堆上分配一块内存,这块内存的使用和销毁的责任都在程 ...
- JVM的逃逸分析
我们都知道Java中的对象默认都是分配到堆上,在调用栈中,只保存了对象的指针.当对象不再使用后,需要依靠GC来遍历引用树并回收内存.如果堆中对象数量太多,回收对象还有整理内存,都会会带来时间上的消耗, ...
- Go 逃逸分析
Go 逃逸分析 堆和栈 要理解什么是逃逸分析会涉及堆和栈的一些基本知识,如果忘记的同学我们可以简单的回顾一下: 堆(Heap):一般来讲是人为手动进行管理,手动申请.分配.释放.堆适合不可预知大小的内 ...
- JVM中启用逃逸分析
-XX:+DoEscapeAnalysis 逃逸分析优化JVM原理我们知道java对象是在堆里分配的,在调用栈中,只保存了对象的指针.当对象不再使用后,需要依靠GC来遍历引用树并回收内存,如果对象数量 ...
- JVM笔记-逃逸分析
参考: http://www.iteye.com/topic/473355http://blog.sina.com.cn/s/blog_4b6047bc01000avq.html 什么是逃逸分析(Es ...
随机推荐
- Linux进程管理之top
关于Linux进程查看,前面讲解了ps命令,下面拉介绍另一个命令top ps:静态查看 top:动态查看 动态查看进程的状态 # top [root@wei ~]# top top - 18:38:4 ...
- Nginx 高级配置--关于favicon.ico
Nginx 高级配置--关于favicon.ico 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.浏览器会默认帮咱们访问官网的图标 1>.浏览器访问网站"htt ...
- AAC的RTP封装中的AU头分析
解码器收到一个RTP的AAC流,发现RTP流里的音频里带有4个字节AU头,然后才是AAC的ADTS头. 这种情况之前已经出现过多次,每次我们都告知对方,不要往AAC前面加AU头,解码器不支 ...
- vue-loader作用
(1)浏览器本身并不认为.vue文件,所以必须对.vue文件进行加载解析,此时需要vue-loader (2)类似的loader还有许多,如:html-loader.css-loader.style- ...
- 缓存中,2个注解:@cacheable 与 @cacheput 的区别
@cacheable:只会执行一次,当标记在一个方法上时表示该方法是支持缓存的,Spring会在其被调用后将其返回值缓存起来,以保证下次利用同样的参数来执行该方法时可以直接从缓存中获取结果. @cac ...
- linux cpu信息查看
转自:https://www.cnblogs.com/emanlee/p/3587571.html # 总核数 = 物理CPU个数 X 每颗物理CPU的核数 # 总逻辑CPU数 = 物理CPU个数 X ...
- 洛谷p1902刺杀大使题解
题目传送门 方法:二分答案+dfs 二分一个mid,此次刺杀的最大伤害,作为判断条件来dfs,二分,更新. 我们二分一个答案mid来表示一个界限,如果当前这个格子的伤害代价比mid小则可以走否则就不走 ...
- Android Studio 之 Navigation【1.页面之间的切换】
1.创建 2个 Fragment ,下面两个include 不要勾 2.创建好 Fragment 后,打开layout中的 fragment.xml 文件,将里面默认的 textView 控件删除掉 ...
- linux 系统时间 EST CST
早上本来要做一些实验的,基于时间的.date 查看时间,发现时间不对.用 pool.ntp.org 去同步发现时间还是一样的,并且没有报错.如是开启另外一台时间对的linux服务器进行对比.发现一个是 ...
- 2 Linux性能优化--工具图