GO的逃逸分析
逃逸分析
前言
指的就是由编译器决定内存分配的位置,不需要由程序员来指定。函数中申请一个新的对象,其目的是为了提高程序的性能,减少内存分配和垃圾回收的开销。
- 分配在 栈 中, 则函数执行结束则可自动将内存回收
- 分配在 堆 中, 则函数执行结束可交给GC(垃圾回收)处理
go语言的逃逸分析遵循下面的两个不变性:
- 指向栈对象的指针不能存在于堆中
- 指向栈对象的指针不能在栈对象回收后存活
逃逸策略
每当函数中申请新的对象时,编译器会根据该对象是否被函数外部引用来决定是否逃逸:
- 如果函数外部
没有引用,则优先放到栈中 - 若函数外部
存在引用,则必定放到堆中
注意: 像函数外部没有引用的对象,也有可能放到堆中,比如内存过大超过栈的存储能力
逃逸场景
指针逃逸
go可以返回局部变量指针,这就是一个典型的变量逃逸案例,如下:
package main
type Student struct {
Name string
Age String
}
func StudentRegister(name string, age int) *Student {
s := new(Student) // 这个局部变量s逃逸到堆中去了
s.Name = name
s.Age = age
return s
}
func main() {
StudentRegister("Lockly", 20)
}
通过编译参数 -gcflags=-m 可以验证编译过程中的逃逸分析:第9行显示”escapes to heap”,代表该行内存分配发生了逃逸现象

这里s会逃逸到堆上,是因为他的类型Student是一个结构体,而结构体的大小是不确定的,这个取决于他的字段。而编译器在编译期间无法确定结构体的大小,所以会将它分配到堆上,来避免栈溢出或者栈扩容的开销。这是一种保守的做法但就是为了确保内存安全。
栈空间不足逃逸
这里分配了一个10000个长度的切片,可以看到编译提示中已经发生了逃逸。实际上就是当栈空间不足以存放当前对象时,或者无法判断当前切片长度时会将对象分配到堆中

动态类型逃逸
这里用编译参数去查看会发现s逃逸了,是因为他被作为参数传入fmt.Println(),这个函数的参数类型是interface{},这时编辑器无法在编译期间确定其具体类型,所以就会被分配到堆上。这是一种变量类型不确定的逃逸情况。
pacakge main
import "fmt"
func main() {
s := "Escape"
fmt.Println(s)
}
// 编译结果
Lockly@BK ❯ go build -gcflags='-m -l'
# demo/escape
.\demo3.go:7:13: ... argument does not escape
.\demo3.go:7:14: s escapes to heap
闭包引用对象逃逸
这里定义的闭包函数fibonacci返回了一个匿名函数func() int, 这个匿名函数引用了外部变量a, b,所以他们不能在栈上面分配,而必须在堆上分配。这是一种 变量生命周期不确定导致的逃逸情况。
package escape
import "fmt"
func fibonacci() func() int {
a, b := 0, 1
return func() int {
a, b = b, a+b
return a
}
}
func main() {
f := fibonacci()
for i := 0; i < 5; i++ {
fmt.Printf("result: %d\n", f())
}
}
决定变量是在栈上还是堆上虽然很重要,但这是一个定义相对清晰的问题。可以通过编译器统一做出决策。为了保证内存的绝对安全,编译器可能会将一些变量错误的分配到堆上面,就像上面的例子那样,但是因为这些堆也会被垃圾收集器处理,所以不会造成内存泄漏以及悬挂指针等安全问题,节省了coder的工作量。
Tips
- 尽量使用值传递而不是指针传递, 除非需要修改参数的值或者参数本身很大
- 尽量避免使用interface{}类型,会导致变量类型不确定的逃逸。
- 尽量避免使用闭包函数,会导致生命周期不确定的逃逸
- 尽量避免使用反射,会导致变量类型不确定的逃逸。
- 尽量使用局部变量而不是全局变量,因为全局变量会导致变量生命周期不确定的逃逸。
- 尽量使用固定大小的数组而不是切片,因为切片可能会导致动态内存分配和逃逸。
GO的逃逸分析的更多相关文章
- JVM中启用逃逸分析
-XX:+DoEscapeAnalysis 逃逸分析优化JVM原理我们知道java对象是在堆里分配的,在调用栈中,只保存了对象的指针.当对象不再使用后,需要依靠GC来遍历引用树并回收内存,如果对象数量 ...
- JVM笔记-逃逸分析
参考: http://www.iteye.com/topic/473355http://blog.sina.com.cn/s/blog_4b6047bc01000avq.html 什么是逃逸分析(Es ...
- Go变量逃逸分析
目录 什么是逃逸分析 为什么要逃逸分析 逃逸分析是怎么完成的 逃逸分析实例 总结 写过C/C++的同学都知道,调用著名的malloc和new函数可以在堆上分配一块内存,这块内存的使用和销毁的责任都在程 ...
- JVM逃逸分析
开启逃逸分析: -server -XX:+DoEscapeAnalysis -XX:+PrintGCDetail -Xmx10m -Xms10m 关闭逃逸分析: -server -XX:-DoEsca ...
- 逃逸分析(Escape Analysis)
一.什么是逃逸 逃逸是指在某个方法之内创建的对象,除了在方法体之内被引用之外,还在方法体之外被其它变量引用到:这样带来的后果是在该方法执行完毕之后,该方法中创建的对象将无法被GC回收,由于其被其它变量 ...
- golang逃逸分析和竞争检测
最近在线上发现一块代码逻辑在执行N次耗时波动很大1ms~800ms,最开始以为是gc的问题,对代码进行逃逸分析,看哪些变量被分配到堆上了,后来发现是并发编程时对一个切片并发的写,导致存在竞争,类似下面 ...
- 深入理解Java中的逃逸分析
在Java的编译体系中,一个Java的源代码文件变成计算机可执行的机器指令的过程中,需要经过两段编译,第一段是把.java文件转换成.class文件.第二段编译是把.class转换成机器指令的过程. ...
- Go 语言机制之逃逸分析
https://blog.csdn.net/weixin_38975685/article/details/79788254 Go 语言机制之逃逸分析 https://blog.csdn.net/ ...
- JVM的逃逸分析
我们都知道Java中的对象默认都是分配到堆上,在调用栈中,只保存了对象的指针.当对象不再使用后,需要依靠GC来遍历引用树并回收内存.如果堆中对象数量太多,回收对象还有整理内存,都会会带来时间上的消耗, ...
- Java之JVM逃逸分析
引言: 逃逸分析(Escape Analysis)是众多JVM技术中的一个使用不多的技术点,本文将通过一个实例来分析其使用场景. 概念 逃逸分析,是一种可以有效减少Java 程序中同步负载和内存堆分配 ...
随机推荐
- ps--提升字体排版的美感四个有效方法
一,文字的摆放位置 (字体的选择不要超过三种,分散注意力)
- CocoaPods 在iOS开发中养活了这么多项目,它到底是个啥?
对于iOS开发者而言,CocoaPods并不陌生,通过pod相关的命令操作,就可以很方便的将项目中用到的三方依赖库资源集成到项目环境中,大大的提升了开发的效率.CocoaPods作为iOS项目的包管理 ...
- 【Python爬虫】使用代理ip进行网站爬取
使用代理IP进行网站爬取可以有效地隐藏你的真实IP地址,让网站难以追踪你的访问行为.本文将介绍Python如何使用代理IP进行网站爬取的实现,包括代理IP的获取.代理IP的验证.以及如何把代理IP应用 ...
- RabbitMQ保姆级教程最佳实践
一.消息队列介绍 1.消息队列概念 1.MQ全称为Message Queue,消息队列(MQ)是⼀种应⽤程序对应⽤程序的通信⽅法. 应⽤程序通过读写出⼊队列的消息(针对应⽤程序的数据)来通信,⽽⽆需专 ...
- 记一次 .NET某账本软件 非托管泄露分析
一:背景 1. 讲故事 中秋国庆长假结束,哈哈,在老家拍了很多的短视频,有兴趣的可以上B站观看:https://space.bilibili.com/409524162 ,今天继续给大家分享各种奇奇怪 ...
- 用AI打造一个属于自己的歌手,让她C位霸气出道
一.前言 今天玩儿点儿特别的,AI大行其道的今天,还没玩过AI模型的程序员绝对不是个好厨子.我本人比较喜欢音乐,但是一直没有出道,很是遗憾.那么今天,我就使用AI模型亲手打造一个堪比真人的歌手,让 ...
- 题解 P7325
前言 数学符号约定 \(a,b,p\):表示任意自然数. \(F_x\):表示广义斐波那契数列的第 \(x\) 项. \(f_x\):表示普通斐波那契数列的第 \(x\) 项. 如非特殊说明,将会按照 ...
- 题解 CF742B
题目大意: 给定 \(n\) 个数,找数对使其异或值为 \(k\),求满足这样数对的个数. 题目分析: 考验位运算功底的题目(实际上也不是很难),主要运用到了下列性质: \[\begin{aligne ...
- 在Dash中更灵活地编写回调函数
本文示例代码已上传至我的Github仓库https://github.com/CNFeffery/dash-master 大家好我是费老师,使用Dash开发过交互式应用的朋友,想必都不会对回调函数感到 ...
- 二、RHEL8操作系统安装
一.如何安装rhel的操作系统? 必要的前提条件:硬件(CPU.内存.硬盘--) + 安装介质(操作系统的安装文件) 会不会把自己的笔记本装成rhel的操作系统呢? 不会 使用虚拟机软 ...