deepwzh的技术笔记
  • Golang
  • Python
  • Cpp
杂项
前端开发
  • 计算机网络
  • 操作系统
  • 数据库
云原生
Devops
AIGC
关于作者
  • Golang
  • Python
  • Cpp
杂项
前端开发
  • 计算机网络
  • 操作系统
  • 数据库
云原生
Devops
AIGC
关于作者
  • Golang
  • 工具
  • 最佳实践
  • 学习资料
  • 代码生成
  • 安装与配置

    • 安装与配置
    • GVM
    • 私有仓库拉取
    • 安装与配置
  • 库

    • 库
    • Grpc-go
    • 命令行参数
    • 依赖注入库 wire
  • 编译器

    • 编译器
    • clean
    • 逃逸分析
    • 编译过程
    • 构建选项
    • 编译优化

      • 编译优化
      • PGO
  • 语言

    • 语言
    • defer
    • go:embed
  • 微服务框架

    • 微服务框架
    • Kratos

      • Kratos
      • 集成三方 web 框架
      • 项目结构体系

逃逸分析

概述

默认分配策略

在没有逃逸分析的情况下,编译器可能会采用以下保守的默认分配策略:

  1. 局部变量:通常会分配在栈上,但如果编译器无法确定其生命周期,则可能会分配在堆上。
  2. 指针变量:如果局部变量的地址被取出并传递到其他函数,编译器可能会将其分配在堆上。
  3. 闭包捕获的变量:这些变量通常会分配在堆上,因为闭包可能在函数返回后仍然存在。

逃逸分析就是,确定哪些变量可以分配在栈上,哪些需要分配在堆上。禁用优化后,更多的变量可能会分配到堆上,增加垃圾收集的负担。

在 Go 语言中,判断一个对象是分配在栈上还是堆上可以通过查看编译器的逃逸分析结果来实现。Go 编译器提供了一个选项,可以在编译时输出逃逸分析的信息,这样你就可以知道哪些变量是分配在堆上,哪些是分配在栈上。

使用 gcflags 选项查看逃逸分析结果

你可以使用 -gcflags="-m" 选项来编译你的程序,并查看编译器输出的逃逸分析信息。具体步骤如下:

  1. 创建一个示例程序:
package main
import "fmt"
func createMap() map[string]int {
    m := make(map[string]int)
    m["key"] = 42
    return m
}
func createSlice() []int {
    s := make([]int, 10)
    s[0] = 42
    return s
}
func main() {
    m := createMap()
    fmt.Println(m)
    s := createSlice()
    fmt.Println(s)
}

使用 gcflags="-m" 选项编译程序:

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

查看编译器输出:

编译器会输出逃逸分析的信息,类似如下:

command-line-arguments
./main.go:6:6: can inline createMap
./main.go:12:6: can inline createSlice
./main.go:7:13: make(map[string]int) does not escape
./main.go:8:13: m["key"] escapes to heap
./main.go:8:13: &m["key"] escapes to heap
./main.go:13:13: make([]int, 10) does not escape
./main.go:14:13: s[0] escapes to heap

解释编译器输出

  • does not escape:表示变量没有逃逸,通常会分配在栈上。
  • escapes to heap:表示变量逃逸了,通常会分配在堆上。

在上述输出中:

  • make(map[string]int) does not escape 表示 map 的初始化没有逃逸,可能会分配在栈上。
  • m["key"] escapes to heap 表示 map 的元素访问逃逸了,导致 map 被分配在堆上。
  • make([]int, 10) does not escape 表示 slice 的初始化没有逃逸,可能会分配在栈上。
  • s[0] escapes to heap 表示 slice 的元素访问逃逸了,导致 slice 的底层数组被分配在堆上。
Prev
clean
Next
编译过程