文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

GoLang逃逸分析讲解

2022-12-15 12:02

关注

概念

当一个对象的指针在被多个方法或者线程引用,称为逃逸分析, 逃逸分析决定一个变量分配在堆上还是栈上, 当然是否发生逃逸是由编译器决定的

分配栈和堆上变量的问题

1.局部变量在栈上(静态分配),函数执行完毕后,自动被栈回收,导致其他对此变量引用出现painc null 指针异常, 栈用户态实现goroutine 作为执行上下文

2.将变量 new 方式分配在堆上(动态分配),堆上有个特点,变量不会被删除,但是会造成内存异常

// 如下代码导致 程序崩溃, 调用栈获取危险的悬挂指针
int *foo ( void)   
{     
int t = 3;
return &t;
} 

1. 栈上分配内存好处: 一般栈内存 2-4 MB
a. 回收快: 减少GC压力,当函数返回回收资源。不需要标记清除
b. 分配快栈分配比堆快,不会有内存碎片
c. 并发快, 清除同步,如果定义对象上有同步锁,却只有一个线程访问,此时逃逸分析机器码 去掉同步锁

总结: 逃逸分析目标:尽可能的使用栈分配内存 go build -gcflags ‘-m -N -l’ 方式编译逃逸分析结果

逃逸分析准则

如果一个函数返回对变量的引用,那么他就发生逃逸

CCN_ProLang/CoreGo/GoreGo 下面有对应的文档参考

逃逸分析大致思路

1.最重要函数 escape.go

$GOROOT/src/cmd/compile/internal/gc/escape.go

1. 首先构建一个有向无环图加权图,顶点(语句和表达式分配的变量),边(代表变量之间的赋值关系)
2. 遍历该有向加权图,图中违反上面两个不变条件的赋值路径,算法还记录每个函数的参数到堆的数据流和其返回值的数据流
权重

// p =&q -1 // 最低值
// p =q 0
// p = *q // 解引用 1
// p = **q 2

示例: root =&L , L 节点的指针指向root, 因此 root有一条边,src 就是L,该权重就是 -1

3. 逃逸分析: 分析 分配内存地方与使用 是否发生逃逸
4. go build -gcflags = "-m -m -m -m -W -W -N -l"

1. 当函数中变量返回值, 它将不可能分配在栈上

2.在循环内被重新赋值的变量大部分场景分配在堆上

3.在闭包外声明的变量在闭包内赋值失效后,需要分配在堆上

是否发生逃逸,这一点使用编译器决定的。导致后果:1. GC频繁导致CPU压力大 2.导致性能下降很大

1. 一些逃逸案例:
2. 函数返回变量取地址 导致逃逸
func GetUserInfo(userInfo UserData) *UserData{
   // 编译器判断外部使用 发生逃逸 ,传入的实参对象 取地址类似复制一份
	return &userInfo
}
//修改 将入参修改成指针, 中间没有新结构体没有变化 没有发生逃逸
func GetUserInfo(userInfo *UserData) *UserData {
		return userInfo
}
案例二:不确定类型逃逸
func MyPrintLn(one interface{}) (n int, err error){
	var userInfo = new(User)
	userInfo.name = one // 泛型赋值逃逸 类型转换时候发生逃逸
	return
}
变量确定具体类型
示例三: 间接变量赋值 闭包
var {
     UserOne User // 值对象
     userTwo = new(User) // 引用对象
}
userOne.name = "one" // 不逃逸
userTwo.name = "two" // 逃逸
userOne.age = new(int) // 不逃逸
userTwo.age = new(int) // 逃逸 引用对象在进行引用对象 只能分配堆上
引用对象: 编译器先分析器userTwo 对象分配到堆上,成员变量name,age 引用类型,保证不出现在栈上 导致对象userTwo 被回收 所有 name,age 需要逃逸
优化建议: 不要将引用对象赋值给引用对象

总结

必然不会发生逃逸的情况:

1. 指针被没有发生逃逸的变量引用

2. 仅仅在函数被对变量进行取地址操作,没有将指针传出

一定逃逸

构造函数new/make 返回的指针变量一定逃逸

2. 被已经逃逸指针变量引用指针,一定发生逃逸

3.指针类型是slice,map,chan 引用指针一定发生逃逸

Maybe 逃逸

将指针作为入参传给别的函数,这里看指针在被传入函数的处理过程,如果发生上边三种情况会逃逸,否则不会

到此这篇关于GoLang逃逸分析讲解的文章就介绍到这了,更多相关Go逃逸内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯