上例中te的类型是func(*int),属于引用类型,参数*int也是引用类型 , 则调用te(j)形成了为te的参数(成员)*int赋值的现象,即te.i = j会导致逃逸 。代码中其他几种调用都没有形成 多级间接赋值 情况 。
同理,如果函数的参数类型是slice,map或interface{}都会导致参数逃逸 。
匿名函数的调用也是一样的 , 它本质上也是一个函数变量 。有兴趣的可以自己测试一下 。
只要使用了Interface类型(不是interafce{}),那么赋值给它的变量一定会逃逸 。因为interfaceVariable.Method()先是间接的定位到它的实际值,再调用实际值的同名方法,执行时实际值作为参数传递给方法 。相当于interfaceVariable.Method.this = realValue
向 channel 中发送数据,本质上就是为 channel 内部的成员赋值,就像给一个 slice 中的某一项赋值一样 。所以chan *Type,chan map[Type]Type,chan []Type,chan interface{}类型都会导致发送到 channel 中的数据逃逸 。
这本来也是情理之中的,发送给 channel 的数据是要与其他函数分享的 , 为了保证发送过去的指针依然可用 , 只能使用堆分配 。
可变参数如func(arg ...string)实际与func(arg []string)是一样的,会增加一层访问路径 。这也是fmt.Sprintf总是会使参数逃逸的原因 。
例子非常多,这里不能一一列举,我们只需要记住分析方法就好,即,2 级或更多级的访问赋值会容易导致数据逃逸 。这里加上容易二字是因为随着语言的发展,相信这些问题会被慢慢解决 , 但现阶段,这个可以作为我们分析逃逸现象的依据 。
下面代码中包含 2 种很常规的写法,但他们却有着很大的性能差距,建议自己想下为什么 。
Benchmark 和 pprof 给出的结果:
熟悉堆栈概念可以让我们更容易看透 Go 程序的性能问题,并进行优化 。
多级间接赋值会导致 Go 编译器出现不必要的逃逸,在一些情况下可能我们只需要修改一下数据结构就会使性能有大幅提升 。这也是很多人不推荐在 Go 中使用指针的原因,因为它会增加一级访问路径 , 而map,slice,interface{}等类型是不可避免要用到的,为了减少不必要的逃逸,只能拿指针开刀了 。
大多数情况下,性能优化都会为程序带来一定的复杂度 。建议实际项目中还是怎么方便怎么写,功能完成后通过性能分析找到瓶颈所在 , 再对局部进行优化 。
C语言里,哪些变量是存放在堆里 , 哪些是存放在栈里?放在堆里的数据是管理员自己开辟空间和释放空间go语言中哪些变量放在栈 , 如,new 和malloc 。
而放在栈里的数据时计算机自动分配内存和释放的,如变量 。
在c/c++中,内存分成5个区,go语言中哪些变量放在栈他们分别是堆、栈、自由存储区、全局/静态存储区和常量存储区 。
1,栈:就是那些由编译器在需要的时候分配,在不需要的时候自动清楚的变量的存储区 。里面的变量通常是局部变量、函数参数等 。
2,堆:就是那些由new分配的内存块,go语言中哪些变量放在栈他们的释放编译器不去管,由我们的应用程序去控制,一般一个new就要对应一个delete 。如果程序员没有释放掉,那么在程序结束后,操作系统会自动回收 。
3,自由存储区:就是那些由malloc等分配的内存块,他和堆是十分相似的,不过它是用free来结束自己的生命的 。
4 , 全局存储区(静态存储区):全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域 , 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域 。程序结束后有系统释放 。
- mysql 判断 mysql的判断语句
- mongodb 创建表 mongodb创建数据库的语法
- mongo sql语句 mongodb写sql语句
- mysql显示表的语句 mysql表示例
- mysql内核 mysql核心语法
- mongodb数据库语句 mongodb数据库文档
- mongodb查询语句大全 mongodb查询最新时间
- redis集群有哪些 redis集群方式有多少
- mongodb哪些企业使用 mongodb适合做业务系统吗
- redis的存储结构有哪些 redis存储的是
