返回顶部
首页 > 资讯 > 后端开发 > GO >golang逃逸的示例分析
  • 946
分享到

golang逃逸的示例分析

2023-06-20 13:06:57 946人浏览 泡泡鱼
摘要

这篇文章主要介绍了golang逃逸的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。垃圾回收是Go的一个很方便的特性--其自动的内存管理使代码更整洁,同时减少内存泄漏的

这篇文章主要介绍了golang逃逸的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。


垃圾回收是Go的一个很方便的特性--其自动的内存管理使代码更整洁,同时减少内存泄漏的可能性。但是,由于垃圾回收需要周期性的停止程序从而去收集不用的对象,不可避免的会增加额外开销。Go编译器是智能的,它会自动决定一个变量是应该分配在堆上从而在将来便于回收,还是直接分配到函数的栈空间。对于分配到栈上的变量,其与分配到堆上的变量不同之处在于:随着函数的返回,栈空间会被销毁,从而栈上的变量被直接销毁,不需要额外的垃圾回收开销。

Go的逃逸分析相对于Java虚拟机的HotSpot来说更为基础。基本规则就是,如果一个变量的引用从声明它的函数中返出去了,则发生“逃逸”,因为它有可能在函数外被别的内容使用,所以必须分配到堆上。如下几种情况会比较复杂:

  • 函数调用其他函数

  • 引用作为结构体的成员变量

  • 切片和映射

  • Cgo指向变量的指针

为了实现逃逸分析,Go会在编译阶段构造函数调用关系图,同时跟踪入参和返回值的流程。一个函数如果只是引用一个参数,但这个引用并没有返出函数的话,这个变量也不会逃逸。如果一个函数返回了一个引用,但是这个引用被栈中的其他函数解除或者没有返回此引用,则也不会逃逸。为了论证几个例子,可以在编译时加-GCflags '-m'参数,这个参数会打印逃逸分析的详细信息:

package maintype S struct {}func main() {    var x S    _ = identity(x)}func identity(x S) S {    return x}

你可以执行go run -gcflags '-m -l'(注:原文中略了go代码文件名)来编译这个代码,-l参数是防止函数identity被内联(换个时间再讨论内联这个话题)。你将会看到没有任何输出!Go使用值传递,所以main函数中的x这个变量总是会被拷贝到函数identity的栈空间。通常情况下没有使用引用的代码都是通过栈空间来分配内存。所以不涉及逃逸分析。下面试下困难一点的:

package maintype S struct {}func main() {    var x S    y := &x    _ = *identity(y)}func identity(z *S) *S {    return z}

其对应的输出是:

./escape.go:11: leaking param: z to result ~r1./escape.go:7: main &x does not escape

第一行显示了变量z的“流经”:入参直接作为返回值返回了。但是函数identity没有取走z这个引用,所以没有发生变量逃逸。在main函数返回后没有任何对x的引用存在,所以x这个变量可以在main函数的栈空间进行内存分配。
第三次实验:

package maintype S struct {}func main() {  var x S  _ = *ref(x)}func ref(z S) *S {  return &z}

其输出为:

./escape.go:10: moved to heap: z./escape.go:11: &z escapes to heap

现在有了逃逸发生。记住Go是值传递的,所以z是对变量x的一个拷贝。函数ref返回一个对z的引用,所以z不能在栈中分配,否则当函数ref返回时,引用会指向何处呢?于是它逃逸到了堆中。其实执行完ref返回到main函数中后,main函数丢弃了这个引用而不是解除引用,但是Go的逃逸分析还不够机智去识别这种情况。
值得注意的是,在这种情况下,如果我们不停止引用,编译器将内联ref
如果结构体成员定义的是引用又会怎样呢?

package maintype S struct {  M *int}func main() {  var i int  refStruct(i)}func refStruct(y int) (z S) {  z.M = &y  return z}

其输出为:

./escape.go:12: moved to heap: y./escape.go:13: &y escapes to heap

在这种情况下,尽管引用是结构体的成员,但Go仍然会跟踪引用的流向。由于函数refStruct接受引用并将其返回,因此y必须逃逸。对比如下这个例子:

package maintype S struct {  M *int}func main() {  var i int  refStruct(&i)}func refStruct(y *int) (z S) {  z.M = y  return z}

其输出为:

./escape.go:12: leaking param: y to result z./escape.go:9: main &i does not escape

尽管在main函数中对i变量做了引用操作,并传递到了函数refStruct中,但是这个引用的范围没有超出其声明它的栈空间。这和之前的那个程序语义上有细微的差别,这个会更高效:在上一个程序中,变量i必须分配在main函数的栈中,然后作为参数拷贝到函数refStruct中,并将拷贝的这一份分配在堆上。而在这个例子中,i仅被分配一次,然后将引用到处传递。

再来看一个有点弯弯绕的例子:

package maintype S struct {  M *int}func main() {  var x S  var i int  ref(&i, &x)}func ref(y *int, z *S) {  z.M = y}

其输出为:

./escape.go:13: leaking param: y./escape.go:13: ref z does not escape./escape.go:9: moved to heap: i./escape.go:10: &i escapes to heap./escape.go:10: main &x does not escape

问题在于,y被赋值给了一个入参结构体的成员。Go并不能追溯这种关系(go只能追溯输入直接流向输出),所以逃逸分析失败了,所以变量只能分配到堆上。由于Go的逃逸分析的局限性,许多变量会被分配到堆上,请参考此链接,这里面记录了许多案例(从Go1.5开始)。

最后,来看下映射和切片是怎样的呢?请记住,切片和映射实际上只是具有指向堆内存的指针的Go结构:slice结构是暴露在reflect包中(SliceHeader
)。map结构就更隐蔽了:存在于hmap。如果这些结构体不逃逸,将会被分配到栈上,但是其底层的数组或者哈希桶中的实际数据会被分配到堆上去。避免这种情况的唯一方法是分配一个固定大小的数组(例如[10000]int)。

如果你剖析过你的程序堆使用情况(https://blog.golang.org/pprof
),并且想减少垃圾回收的消耗,可以将频繁分配到堆上的变量移到栈上,可能会有较好的效果。进一步研究HotSpot JVM是如何进行逃逸分析的会是一个不错的话题,可以参考这个链接,这个里面主要讲解了栈分配,以及有关何时可以消除同步的检测。

感谢你能够认真阅读完这篇文章,希望小编分享的“golang逃逸的示例分析”这篇文章对大家有帮助,同时也希望大家多多支持编程网,关注编程网GO频道,更多相关知识等着你来学习!

您可能感兴趣的文档:

--结束END--

本文标题: golang逃逸的示例分析

本文链接: https://lsjlt.com/news/296806.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • golang逃逸的示例分析
    这篇文章主要介绍了golang逃逸的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。垃圾回收是Go的一个很方便的特性--其自动的内存管理使代码更整洁,同时减少内存泄漏的...
    99+
    2023-06-20
  • GoLang逃逸分析讲解
    目录概念逃逸分析准则逃逸分析大致思路概念 当一个对象的指针在被多个方法或者线程引用,称为逃逸分析, 逃逸分析决定一个变量分配在堆上还是栈上, 当然是否发生逃逸是由编译器决定的 分配栈...
    99+
    2022-12-15
    GoLang逃逸 Go逃逸
  • Go逃逸分析示例详解
    目录引言大纲逃逸分析内存管理栈堆堆和栈的对比加锁性能缓存策略逃逸分析优势逃逸分析原则逃逸分析举例1.参数是interface类型2. 变量在函数外部有引用3. 变量内存占用较大4. ...
    99+
    2024-04-02
  • ​golang面试题之内存逃逸的示例分析
    这篇文章将为大家详细讲解有关golang面试题之内存逃逸的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。问题知道golang的内存逃逸吗?什么情况下会发生内存逃逸?怎么答golang程序变量会携带...
    99+
    2023-06-14
  • Golang学习之内存逃逸分析
    目录内存分配中的堆栈栈堆内存逃逸逃逸分析分析工具逃逸场景逃逸分析的作用在开始剖析Go逃逸分析前,我们要先清楚什么是堆栈。数据结构中有堆栈,内存分配中也有堆栈,两者在定义和用途上虽不同...
    99+
    2023-01-29
    Golang内存逃逸分析 Golang内存逃逸
  • 浅析Golang中的内存逃逸
    目录什么是内存逃逸分析为什么需要逃逸分析如果变量放错了位置会怎样内存逃逸场景return 局部变量的指针interface{} 动态类型栈空间不足闭包性能最后什么是内存逃逸分析 内存...
    99+
    2024-04-02
  • PHP反序列化字符串逃逸的示例分析
    这篇文章将为大家详细讲解有关PHP反序列化字符串逃逸的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。0CTF 2016piapiapia由于是代码审计,直接访问www.zip发现备份的源码,有一下...
    99+
    2023-06-06
  • Java逃逸分析的基本概念
    这篇文章主要介绍Java逃逸分析的基本概念,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!概念引入我们都知道,Java 创建的对象都是被分配到堆内存上,但是事实并不是这么绝对,通过对Java对象分配的过程分析,可以知道...
    99+
    2023-05-30
    java
  • JVM内存增强之逃逸分析
    目录概念逃逸分析参数设计使用逃逸分析FAQ概念 逃逸分析一种数据分析算法,基于此算法可以有效减少 Java 对象在堆内存中的分配。 Hotspot 虚拟机的编译器能够分析出一个新对象...
    99+
    2024-04-02
  • 逃逸分析显示通道作为泄漏参数
    目前编程网上已经有很多关于Golang的文章了,自己在初次阅读这些文章中,也见识到了很多学习思路;那么本文《逃逸分析显示通道作为泄漏参数》,也希望能帮助到大家,如果阅读完后真的对你学习Golang有...
    99+
    2024-04-05
  • php反序列化之字符串逃逸实例分析
    这篇文章主要讲解了“php反序列化之字符串逃逸实例分析”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“php反序列化之字符串逃逸实例分析”吧!php反序列化–字符串逃逸PHP反序列化的字符串逃...
    99+
    2023-06-30
  • 简述Java编程语言中的逃逸分析
            大家一般认为new出来的对象都是被分配在堆上,但这并不是完全正确,通过对Java对象分配过程分析,我们发现对象除了可以被分配在堆上,还可以在栈或TLAB中...
    99+
    2023-05-31
    java 编程语言 逃逸分析
  • 一文搞懂Golang中的内存逃逸
    目录前言什么是内存逃逸查看对象是否发生逃逸内存逃逸分析的意义怎么避免内存逃逸小结前言 我们都知道go语言中内存管理工作都是由Go在底层完成的,这样我们可以不用过多的关注底层的内存问题...
    99+
    2024-04-02
  • golang内存逃逸的原因有哪些
    在Go语言中,内存逃逸指的是在函数执行过程中,将局部变量分配在堆上而不是栈上。内存逃逸会导致额外的性能开销,并可能导致垃圾回收器更频...
    99+
    2023-10-23
    golang
  • golang内存逃逸的情况有哪些
    在Go语言中,内存逃逸是指在函数中创建的变量被分配在堆上而不是栈上。以下是一些常见的导致内存逃逸的情况:1. 在函数中返回局部变量的...
    99+
    2023-10-21
    golang
  • golang内存逃逸的场景有哪些
    在Go语言中,当一个变量在函数内部被分配的时候,该变量要么被分配在栈上,要么被分配在堆上。如果一个变量被分配在栈上,那么它的生命周期...
    99+
    2024-02-29
    golang
  • Go语言中的逃逸分析究竟是什么?
    目录1、逃逸分析介绍2、Go中内存分配在哪里?3、Go与C++内存分配的区别4、逃逸分析骚操作5、逃逸分析引申示例说明 1、逃逸分析介绍 学计算机的同学都知道,在编译原理中,分析指针...
    99+
    2024-04-02
  • 分析Golang变量逃逸现象的性能问题及其优化方法
    Golang变量逃逸原理解析与性能优化 引言:在Golang程序中,变量的逃逸是一个常见的问题,影响着程序的性能和运行效率。本文将深入探讨Golang变量逃逸的原理,并给出一些性能优化的建议。同时,我们还将提...
    99+
    2024-01-18
    性能优化 原理解析
  • Golang中变量逃逸原理底层机制的深入解析
    深入理解Golang中变量逃逸原理的底层机制,需要具体代码示例 在Golang中,变量逃逸是指在函数中定义的局部变量在函数结束后仍然可以被其他地方引用的情况。这个现象看似简单,但背后涉及到Golang的内存管...
    99+
    2024-01-18
    Golang 底层机制 变量逃逸
  • Go语言中内存管理逃逸分析详解
    目录1. 前言2. 逃逸策略3. 逃逸场景3.1 指针逃逸3.2 栈空间不足逃逸3.3 动态类型逃逸3.4 闭包引用对象逃逸4.逃逸总结5. 注意事项1. 前言 所谓的逃逸分析(Es...
    99+
    2023-03-15
    Go 内存管理逃逸分析 Go 内存管理逃逸 Go 内存管理
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作