教程集 www.jiaochengji.com
教程集 >  Golang编程  >  golang教程  >  正文 go语言杂谈-----函数返回局部变量问题(“逃逸分析”)

go语言杂谈-----函数返回局部变量问题(“逃逸分析”)

发布时间:2022-01-14   编辑:jiaochengji.com
教程集为您提供go语言杂谈-----函数返回局部变量问题(“逃逸分析”)等资源,欢迎您收藏本站,我们将为您提供最新的go语言杂谈-----函数返回局部变量问题(“逃逸分析”)资源

<span class="img-wrap"></span>

<pre><code> 在说“逃逸分析”之前,先来啰嗦一下go语言中指针的基本用法,熟悉的看官可以直接跳过这一部分。</code></pre> <h2>1. 指针</h2> <blockquote>Go语言支持指针,通过在变量名前加&来获取变量的地址。
(1) 指针的简单使用,示例如下:</blockquote> <pre><code> year := 2020 ptr := &year // 打印ptr的类型和值 fmt.Printf("%T %v\n", ptr, ptr) // *int 0xc00000a0c8 // 通过指针解引用的形式获取year的值 fmt.Println(*ptr) // 2020 // 直接通过变量名获取year的值 fmt.Println(year) // 2020</code></pre>

(2) 结构体指针访问结构体字段仍然使用"."点操作符,Go语言中没有"->"操作符。示例如下:

<pre><code> package main import "fmt" type User struct { name string age int } func main() { user := User{ name:"lioney", age:18, } ptr := &user fmt.Println(ptr.name, ptr.age) // lioney 18 }</code></pre>

(3) Go语言不支持指针的运算

<blockquote>Go语言由于支持垃圾回收,如果支持指针运算,则会给垃圾回收的实现带来很多不便,在C和C 里面指针运算很容易出现问题,因此Go直接在语言层面禁止指针运算。代码如下:</blockquote> <pre><code> year := 2020 ptr := &year ptr // invalid operation: ptr (non-numeric type *int)</code></pre> <h2>2. Go语言返回函数内的局部变量</h2> <h3>(1)返回函数内局部变量的值:</h3> <ul><li>在C/C 语言中,局部变量分配在栈空间,因为函数返回后,系统会自动回收函数里定义的局部变量,所以在返回局部变量的值时,实际是返回局部变量的副本。</li> <li>在Go语言中返回局部变量的值也是一样的,返回的也是局部变量的副本。代码如下:</li> </ul><pre><code> package main import "fmt" func foo() int { //int类型函数 tmp := 1 fmt.Println(&tmp) // 0xc00000a0e0 return tmp //返回局部变量 } func main() { v := foo() fmt.Println(&v) // 0xc00000a0c8(和tmp地址不同) }</code></pre> <h3>(2)返回函数内局部变量的地址</h3> <ul><li>在C/C 语言中,操作函数返回后的局部变量的地址,一定会发生空指针异常。要解决这种问题,只需将内存空间分配在堆中即可。</li> <li>但在Go语言中,函数内部局部变量,无论是动态new出来的变量还是创建的局部变量,它被分配在堆还是栈,是由编译器做“逃逸分析”之后做出的决定。 </li> <li>

关于Go语言的“逃逸分析”,可以参考go FAQ里的讲解,大意如下:

<ul><li>Go编译器在给函数中的局部变量分配空间时会尽可能地分配在栈空间中,但是如果编译器无法证明函数返回后是否还有该变量的引用存在,则编译器为避免悬挂空指针的错误,就会将该局部变量分配在堆空间中; </li> <li>如果局部变量占用内存很大,Go编译器会认为将其存储在堆空间中更有意义;</li> <li>Go编译器如果看到了程序中有使用某个变量的地址,则该变量会变成在堆空间上分配内存的候选对象,此时Go编译器会通过分析,判断出该指针的使用会不会超过函数的范围,如果没超过,该变量就可以驻留在栈空间上;如果超过了,就必须将其分配在堆空间中。 </li> </ul></li> </ul><blockquote>对于Go语言中的“逃逸分析”,我们可以看下面的代码:</blockquote> <pre><code> package main import "fmt" func foo() *int { // 返回int类型指针 tmp := 2020 return &tmp // 返回局部变量tmp的地址 } func main() { var ptr *int // main函数中引用了foo函数内的局部变量tmp // 根据“逃逸分析”,编译器会将其分配在堆空间上 ptr = foo() // foo函数执行结束后tmp不会被释放 fmt.Println(*p) // 结果为2020,不会报错 }</code></pre> <ul><li>但是,无论局部变量分配在堆空间还是栈空间上,我们都不用担心内存泄漏问题,因为Go语言有强大的垃圾回收机制。Go语言声称这样可以释放程序员关于内存的使用限制,更多的让程序员关注于程序功能逻辑本身。</li> <li>同时,我们也应该知道,变量保存的位置会影响程序的运行效率,在某些场景下,我们需要考虑编译器的“逃逸分析”可能产生的影响。</li> </ul><h2>参考文献</h2> <ol><li>博客https://blog.csdn.net/li_1013... </li> <li>李文塔《Go语言核心编程》第一章相关内容</li> </ol>

<span class="img-wrap"></span>

<blockquote> 我是lioney,年轻的后端攻城狮一枚,爱钻研,爱技术,爱分享。
个人笔记,整理不易,感谢阅读、点赞和收藏。
文章有任何问题欢迎大家指出,也欢迎大家一起交流后端各种问题! </blockquote> 到此这篇关于“go语言杂谈-----函数返回局部变量问题(“逃逸分析”)”的文章就介绍到这了,更多文章或继续浏览下面的相关文章,希望大家以后多多支持JQ教程网!

您可能感兴趣的文章:
go语言杂谈-----函数返回局部变量问题(“逃逸分析”)
go 手动释放内存_Go语言-逃逸分析
golang 日志分析_Golang 内存分配之逃逸分析
详解Go逃逸分析
【golang】逃逸分析
Go语言---函数返回局部变量地址
golang 的GC原理
Go中string转[]byte的陷阱
go 只使用函数返回的一个值_详解二:Go 语言机制之逃逸分析
Go 语言机制之逃逸分析

[关闭]
~ ~