当前位置: 首页 > news >正文

Golang——逃逸分析

逃逸分析是指由编译器决定内存分配到堆上还是栈上。当我们在函数中申请了一个新的对象:

  • 如果分配到栈中,则函数执行结束后可自动将内存回收。
  • 如果分配到堆中,则函数执行结束后,不会自动将内存释放掉,需要GC在进行清除。

逃逸分析使Go语言能够将局部变量返回,程序员不需要担心局部变量分配到栈上还是堆上。并且Go程序员不需要像C程序员一样,担心内存泄漏的问题。

逃逸策略:

在函数中申请一个新的对象时,编译器会根据该对象是否被函数外部引用来确定是否逃逸。

  • 如果变量在函数外部没有引用,则优先放到栈上。
  • 如果变量在函数外部存在引用,则必定放到堆上。

注意,对于一个仅在函数内部使用的变量,也有可能放到堆上,比如内存过大超过栈的存储能力。我们很难通过肉眼直接判断函数内部的变量是否发生了逃逸,我们需要借助go build -gcflags=-m指令判断是否发生逃逸分析。

逃逸场景:

1.函数返回指针,会发生指针逃逸。如果我们的返回的结构体中包含指针,也会发生逃逸,比如slice、 map。

func main() {getNum()
}
func getNum() *int {i := 1return &i
}# ExpertProgramming/chapter04/escape/move_to_heap
./main.go:6:6: can inline getNum
./main.go:3:6: can inline main
./main.go:4:8: inlining call to getNum
./main.go:7:2: moved to heap: i

2.栈空间不足以存放当前创建的对象时,会将新创建的对象分配到堆上,发生逃逸。

func main() {s := make([]int, 1000000, 1000001)for index, value := range s {fmt.Println(index, value)}
}./main.go:10:14: inlining call to fmt.Println
./main.go:8:11: make([]int, 1000000, 1000001) escapes to heap
./main.go:10:14: ... argument does not escape
./main.go:10:15: index escapes to heap
./main.go:10:22: value escapes to heap

3.在编译期间很难确定其对象的具体类型时,会发生逃逸。比如参数为interface类型的函数

func main() {s := "wang"fmt.Println(s)
}./main.go:9:13: inlining call to fmt.Println
./main.go:9:13: ... argument does not escape
./main.go:9:14: s escapes to heap

4.闭包的引用对象

func main() {num := Fibonacci()for i := 0; i < 10; i++ {fmt.Println(num())}
}func Fibonacci() func() int {a, b := 0, 1return func() int {a, b = b, a+breturn a}
}./main.go:10:14: ... argument does not escape
./main.go:10:18: ~R0 escapes to heap
./main.go:15:2: moved to heap: a
./main.go:15:5: moved to heap: b
./main.go:16:9: func literal escapes to heap

5.切片长度不确定的时候也会发生逃逸,即使这时候我们不返回切片

func main() {getSlice()
}func getSlice() {length := 3s1 := make([]int, length)s1[0] = 9
}./main.go:7:6: can inline getSlice
./main.go:3:6: can inline main
./main.go:4:10: inlining call to getSlice
./main.go:4:10: make([]int, length) escapes to heap
./main.go:9:12: make([]int, length) escapes to heap

总结:

逃逸分析的目的是为了确定对象分配到了堆上还是分配到了栈上。有了逃逸分析,我们可以非常方便地返回函数里面的变量,这方便了我们的开发,但也有可能会造成我们程序的性能下降。因为分配到堆上的变量,需要GC进行回收。而GC运行的时候,会发生STW。所以,我们要减少不合理的逃逸现象,减轻GC的负担。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • MindSearch:AI 时代的“思考型”搜索引擎
  • EasyExcel 自定义转换器、自定义导出字典映射替换、满足条件内容增加样式
  • Python 之Scikit-learn(三) -- 使用Scikit-learn进行数据归一化
  • 八股(1)
  • 中超股份五年坎坷资本梦:毛利率下滑,连年大额分红还募投补流
  • 利用SSH实现分布式应用的一键安装部署①(多主机执行指令函数封装、日志输出、关闭防火墙、传输文件函数封装)
  • Qt无边框窗口,关闭后再show,鼠标等事件不响应问题解决办法
  • elasticsearch的使用(二)
  • MYSQL知识点(持续更新)
  • 详解Xilinx FPGA高速串行收发器GTX/GTP(4)--TX/RX接口的数据位宽和时钟设计
  • 【Python机器学习】支持向量机——在复杂数据上应用核函数
  • 27集28集 ESP32 AIchat cmake编译解密-《MCU嵌入式AI开发笔记》
  • 谷粒商城实战笔记-nginx问题记录
  • 服务器测试之RAID知识梳理
  • MySQL的三大关键日志:Bin Log、Redo Log与Undo Log
  • [NodeJS] 关于Buffer
  • [译] 理解数组在 PHP 内部的实现(给PHP开发者的PHP源码-第四部分)
  • [译] 怎样写一个基础的编译器
  • 【许晓笛】 EOS 智能合约案例解析(3)
  • axios 和 cookie 的那些事
  • CSS选择器——伪元素选择器之处理父元素高度及外边距溢出
  • gcc介绍及安装
  • GDB 调试 Mysql 实战(三)优先队列排序算法中的行记录长度统计是怎么来的(上)...
  • iOS | NSProxy
  • node和express搭建代理服务器(源码)
  • PHP面试之三:MySQL数据库
  • spring boot 整合mybatis 无法输出sql的问题
  • vue2.0开发聊天程序(四) 完整体验一次Vue开发(下)
  • 分享自己折腾多时的一套 vue 组件 --we-vue
  • 湖南卫视:中国白领因网络偷菜成当代最寂寞的人?
  • 驱动程序原理
  • 让你成为前端,后端或全栈开发程序员的进阶指南,一门学到老的技术
  • 使用parted解决大于2T的磁盘分区
  • 原生JS动态加载JS、CSS文件及代码脚本
  • 正则表达式
  • 06-01 点餐小程序前台界面搭建
  • 基于django的视频点播网站开发-step3-注册登录功能 ...
  • ​​​​​​​​​​​​​​汽车网络信息安全分析方法论
  • ​人工智能之父图灵诞辰纪念日,一起来看最受读者欢迎的AI技术好书
  • (LeetCode 49)Anagrams
  • (python)数据结构---字典
  • (二)测试工具
  • (分享)自己整理的一些简单awk实用语句
  • (附源码)ssm基于web技术的医务志愿者管理系统 毕业设计 100910
  • (附源码)计算机毕业设计ssm本地美食推荐平台
  • (南京观海微电子)——COF介绍
  • (删)Java线程同步实现一:synchronzied和wait()/notify()
  • (提供数据集下载)基于大语言模型LangChain与ChatGLM3-6B本地知识库调优:数据集优化、参数调整、Prompt提示词优化实战
  • (已更新)关于Visual Studio 2019安装时VS installer无法下载文件,进度条为0,显示网络有问题的解决办法
  • (转) Android中ViewStub组件使用
  • (转)chrome浏览器收藏夹(书签)的导出与导入
  • (转)关于如何学好游戏3D引擎编程的一些经验
  • **PHP二维数组遍历时同时赋值
  • *p=a是把a的值赋给p,p=a是把a的地址赋给p。
  • .net core 客户端缓存、服务器端响应缓存、服务器内存缓存