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

Go的内存逃逸

Go的内存逃逸

内存逃逸是 Go 语言中一个重要的概念,指的是本应分配在栈上的变量被分配到了堆上。栈上的变量在函数结束后会自动回收,而堆上的变量需要通过垃圾回收(GC)来管理,因此内存逃逸会增加 GC 的压力,影响程序性能。
在这里插入图片描述


1. 什么是内存逃逸?

内存逃逸是指本应分配在栈上的变量,由于某些原因被分配到了堆上。栈上的变量在函数结束后会自动回收,而堆上的变量需要通过垃圾回收(GC)来管理。

栈和堆的区别
    • 分配和回收速度快。
    • 变量生命周期与函数绑定,函数结束后自动回收。
    • 适合存储局部变量和小型数据。
    • 分配和回收速度较慢。
    • 变量生命周期不固定,需要 GC 管理。
    • 适合存储大型数据或需要跨函数共享的数据。

2. 内存逃逸的影响

内存逃逸会增加 GC 的压力,影响程序性能:

  • 性能开销:堆上的变量需要通过 GC 回收,增加了额外的性能开销。
  • 延迟增加:GC 的执行可能会导致程序暂停(STW),增加延迟。

3. 内存逃逸的发生条件

以下是一些常见的内存逃逸场景:

3.1 方法内返回局部变量指针
  • 原因:局部变量的指针被返回,导致其生命周期超出函数范围。
package main

import "fmt"

func foo() *int {
    x := 42
    return &x // x 逃逸到堆上
}

func main() {
    p := foo()
    fmt.Println(*p) // 输出: 42
}
3.2 向 channel 发送指针数据
  • 原因:指针数据被发送到 channel,可能导致其生命周期超出当前函数。
package main

import "fmt"

func foo(ch chan *int) {
    x := 42
    ch <- &x // x 逃逸到堆上
}

func main() {
    ch := make(chan *int, 1)
    foo(ch)
    p := <-ch
    fmt.Println(*p) // 输出: 42
}
3.3 在闭包中引用包外的值
  • 原因:闭包中引用的外部变量需要延长其生命周期。
package main

import "fmt"

func foo() func() int {
    x := 42
    return func() int {
        return x // x 逃逸到堆上
    }
}

func main() {
    f := foo()
    fmt.Println(f()) // 输出: 42
}
3.4 在 slice 或 map 中存储指针
  • 原因:slice 或 map 中存储的指针可能导致其生命周期超出当前函数。
package main

import "fmt"

func foo() []*int {
    x := 42
    return []*int{&x} // x 逃逸到堆上
}

func main() {
    s := foo()
    fmt.Println(*s[0]) // 输出: 42
}
3.5 切片(扩容后)长度太大
  • 原因:切片扩容后,数据可能被重新分配到堆上。
package main

import "fmt"

func foo() {
    s := make([]int, 0, 10)
    for i := 0; i < 10000; i++ {
        s = append(s, i) // s 可能逃逸到堆上
    }
    fmt.Println(len(s)) // 输出: 10000
}

func main() {
    foo()
}
3.6 在 interface 类型上调用方法
  • 原因:interface 类型的动态分发可能导致变量逃逸。
package main

import "fmt"

type MyInterface interface {
    DoSomething()
}

type MyStruct struct {
    x int
}

func (m *MyStruct) DoSomething() {
    fmt.Println(m.x)
}

func foo() MyInterface {
    x := 42
    return &MyStruct{x} // x 逃逸到堆上
}

func main() {
    obj := foo()
    obj.DoSomething() // 输出: 42
}

Mermaid 流程图

以下是内存逃逸的流程图:

变量定义
是否逃逸?
分配到堆上
分配到栈上
GC 管理
函数结束后自动回收

http://www.kler.cn/a/518164.html

相关文章:

  • Redis数据库笔记——数据结构类型
  • Android程序中使用FFmpeg库
  • 大模型语料库的构建过程 包括知识图谱构建 垂直知识图谱构建 输入到sql构建 输入到cypher构建 通过智能体管理数据生产组件
  • 【论文+源码】Difformer在文本生成嵌入空间上增强扩散模型
  • RV1126画面质量一:视频基础
  • 【Linux系统】—— 动静态库
  • ORB-SLAM2源码学习:Initializer.cc(13): Initializer::ReconstructF用F矩阵恢复R,t及三维点
  • 【力扣Hot 100】矩阵1
  • go replay流量重放[详细教程]
  • JS 正则表达式 -- 分组【详解】含普通分组、命名分组、反向引用
  • 豆包 MarsCode + 开源 = ?AI 助力开源社区新人成长
  • JVM学习指南(48)-JVM即时编译
  • 2025美赛数学建模ICM问题F:网络强大?(Problem F: Cyber Strong?)完整文章 模型 数据 源代码 结果分享
  • Jenkins下线实例报错
  • 罗永浩的“最后一次创业”:从AR到AI大模型的战略转型
  • Spring 源码学习(七)——注解后处理器-2
  • SpringBoot支持动态更新配置文件参数
  • 群辉部署集2 Neo4j
  • 一文了解神经网络和模型训练过程
  • java入门基础笔记语法篇(3)