浅谈go语言内存逃逸现象

 更新时间:2025年10月19日 11:46:10   作者:砖心搬砖  
本文主要介绍了浅谈go语言内存逃逸现象,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

什么是逃逸分析?

Go 的编译阶段发生在您执行 go build、go install 或 go run 命令时,编译器执行的一个静态分析步骤,它通过分析代码的作用域和生命周期,来判断一个局部变量(通常在栈上分配)是否“逃逸”出了它原本的声明范围(比如函数返回后还需要存在)。如果逃逸了,那么这个变量就必须在堆上分配,以便在函数返回后还能被访问。

逃逸分析发生在哪个阶段?

逃逸分析发生在你之前问题中提到的 编译流程的早期阶段,具体是在:

类型检查之后(因为需要类型信息)。

生成中间代码之前。

所以,它是在纯粹的编译时做出的决定,而不是在运行时。

编译器如何决定:栈 vs. 堆?

编译器遵循一个基本原则:只要编译器能证明函数返回后,该变量不再被引用,那么它就会被分配在栈上。否则,就必须分配在堆上。

以下是导致变量逃逸到堆上的常见情况:

  1. 返回局部变量的指针
    这是最典型的例子。如果函数返回了一个局部变量的地址,那么这个局部变量必须在堆上分配,因为它在函数返回后依然有效。
func foo() *int {
    v := 100 // 局部变量 v
    return &v // 返回 v 的地址。v 会逃逸到堆上。
}

func main() {
    p := foo()
    fmt.Println(*p)
}
  1. 将指针存储到全局变量或包级变量中
    局部变量的生命周期超过了函数本身,因此必须分配在堆上。
var global *int

func bar() {
    x := 1 // x 会逃逸到堆上,因为 global 在 bar 函数返回后仍然存在。
    global = &x
}
  1. 发送指针或带有指针的值到 Channel
    Go 的 Channel 是引用类型,发送操作可能导致变量被其他 goroutine 访问,其生命周期无法在编译时确定,因此会逃逸。
type Data struct {
    S string
}

func main() {
    ch := make(chan *Data, 1)
    d := Data{S: "hello"} // d 会逃逸到堆上
    ch <- &d
}
  1. 在切片或 Map 中存储指针
    如果切片或 Map 本身逃逸了(比如被返回了),那么其中存储的指针所指向的变量也会逃逸。
func getMap() map[string]*int {
    m := make(map[string]*int)
    val := 10 // val 会逃逸到堆上
    m["key"] = &val
    return m
}
  1. 由于动态大小或接口调用
    当切片的大小在编译时无法确定(比如根据参数动态分配),或者值被存储到 interface{} 中(因为接口的方法调用是动态的),编译器可能会采取保守策略,让其逃逸。
func createSlice(n int) {
    s := make([]int, n) // 如果 n 非常大或者在编译时未知,s 可能会逃逸
    // ... 使用 s
}

逃逸分析命令

go build -gcflags="-m -l" main.go

总结

从专业角度看,内存逃逸是 Go 语言内存管理系统的核心机制之一:

安全性优先:逃逸分析确保指针始终指向有效内存,避免悬垂指针

编译时决策:在编译阶段确定变量分配位置,而非运行时

性能权衡:在内存安全性和执行效率之间取得平衡

透明性:对开发者透明,但了解机制有助于写出更高效的代码

到此这篇关于浅谈go语言内存逃逸现象的文章就介绍到这了,更多相关go语言内存逃逸内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • go语言转换json字符串为json数据的实现

    go语言转换json字符串为json数据的实现

    本文主要介绍了go语言转换json字符串为json数据的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2025-03-03
  • Go语言里切片slice的用法介绍

    Go语言里切片slice的用法介绍

    这篇文章介绍了Go语言里切片slice的用法,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-07-07
  • Go语言实现单端口转发到多个端口

    Go语言实现单端口转发到多个端口

    这篇文章主要为大家详细介绍了Go语言实现单端口转发到多个端口,文中的示例代码讲解详细,具有一定的参考价值,对大家的学习或工作有一定的帮助,需要的小伙伴可以了解下
    2024-02-02
  • go实现整型的二进制转化的方法

    go实现整型的二进制转化的方法

    这篇文章主要介绍了go实现整型的二进制转化的方法,本文给大家介绍的非常详细,具有一定的参考借鉴价值 ,需要的朋友可以参考下
    2019-07-07
  • go中的参数传递是值传递还是引用传递的实现

    go中的参数传递是值传递还是引用传递的实现

    参数传递机制是一个重要的概念,它决定了函数内部对参数的修改是否会影响到原始数据,本文主要介绍了go中的参数传递是值传递还是引用传递的实现,感兴趣的可以了解一下
    2024-12-12
  • Golang中实现数据脱敏处理的go-mask包分享

    Golang中实现数据脱敏处理的go-mask包分享

    这篇文章主要是来和大家分享一个在输出中对敏感数据进行脱敏的工作包:go-mask,可以将敏感信息输出的时候替换成星号或其他字符,感兴趣的小编可以跟随小编一起了解下
    2023-05-05
  • golang通过反射手动实现json序列化的方法

    golang通过反射手动实现json序列化的方法

    在 Go 语言中,JSON 序列化和反序列化通常通过标准库 encoding/json 来实现,本文给大家介绍golang  通过反射手动实现json序列化的方法,感兴趣的朋友一起看看吧
    2024-12-12
  • Go位集合相关操作bitset库安装使用

    Go位集合相关操作bitset库安装使用

    这篇文章主要为大家介绍了Go位集合相关操作bitset库安装使用,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-07-07
  • golang如何获得一个变量的类型

    golang如何获得一个变量的类型

    这篇文章主要介绍了golang获得一个变量类型的实现方式,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-05-05
  • GO语言短变量声明的实现示例

    GO语言短变量声明的实现示例

    在Go语言中,短变量声明是一种简洁的变量声明方式,使用 := 运算符,可以自动推断变量类型,下面就来具体介绍一下如何使用,感兴趣的可以了解一下
    2025-08-08

最新评论