Go语言中内存逃逸分析是如何进行的?

2026-05-22 15:391阅读0评论SEO资讯
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计741个文字,预计阅读时间需要3分钟。

Go语言中内存逃逸分析是如何进行的?

Go的内存逃逸及分析:Go的内存逃逸涉及对内存的优化使用。分析内存逃逸前,需解决一些基础问题。我们的程序中的函数和局部变量默认存储在栈上。栈上存储的数据指针指向堆上的数据。

Go的内存逃逸及逃逸分析 Go的内存逃逸

分析内存逃逸之前要搞清楚一件事 我们编写的程序中的函数局部变量默认是存放在栈上的(补充一点堆上存储的数据的指针 是存放在栈上的 因为指针的大小是可以提前预知的 还有就是Go的基本类型也是存放在栈内的), 而其余的变量是存在堆上的, 栈是由操作系统层面控制 进行内存空间的释放 , 堆默认是程序控制的 像c c++ 是需要标明释放内存空间的位置 , 栈的运行速度远大于堆 . 拥有GC的高级语言回收的便是堆中的内容

  • Go编译器查看内存逃逸的结果 go build -gcflags=-m xxx.go
  • 发生内存逃逸的场景
  1. 函数返回局部变量是一个指针变量

# type User struct { Name string } func name(s string) *User { u := new(User) # 这个变量的类型是 *User 指针变量 u.Name = s return u } func main() { user := name("kuQi") fmt.Println(user) } # command-line-arguments ./main.go:9:6: can inline name ./main.go:18:14: inlining call to name ./main.go:19:13: inlining call to fmt.Println ./main.go:9:11: leaking param: s ./main.go:10:10: new(User) escapes to heap // 造成逃逸 ./main.go:18:14: new(User) escapes to heap // 造成逃逸 ./main.go:19:13: []interface {}{...} does not escape <autogenerated>:1: leaking param content: .this

2.interface的动态类型造成的内存逃逸

Go语言中内存逃逸分析是如何进行的?

// fmt.Println 接受的参数就是interface动态类型 编译器很难确定接收变量的类型 所有会将123这个变量逃逸到堆 func main() { fmt.Println(123) } # command-line-arguments ./main.go:16:6: can inline main ./main.go:20:13: inlining call to fmt.Println ./main.go:20:14: 123 escapes to heap ./main.go:20:13: []interface {}{...} does not escape <autogenerated>:1: leaking param content: .this

3.闭包函数产生的内存逃逸

// 因为函数也是一个指针类型 所以将匿名函数作为返回值时 也会产生内存逃逸 原理类似于 第一个 原因 func BiBao() func() string { return func() string { return "test" } } # command-line-arguments ./main.go:24:9: func literal escapes to heap: ./main.go:24:9: flow: ~r0 = &{storage for func literal}: ./main.go:24:9: from func literal (spill) at ./main.go:24:9 ./main.go:24:9: from return func literal (return) at ./main.go:24:2 ./main.go:24:9: func literal escapes to heap

4.变量大小无法确定 或 栈空间不足 引发内存逃逸

ulimit -a // ulimit -a 可以看到我们的栈空间是8192 -t: cpu time (seconds) unlimited -f: file size (blocks) unlimited -d: data seg size (kbytes) unlimited -s: stack size (kbytes) 8192 -c: core file size (blocks) 0 -v: address space (kbytes) unlimited -l: locked-in-memory size (kbytes) unlimited -u: processes 2784 -n: file descriptors 2560 // 超大切片超出栈空间 引发的内存逃逸 package main func main() { s := make([]int, 10000, 10000) // 创建一个超大切片 for index, _ := range s { s[index] = index } }

本文共计741个文字,预计阅读时间需要3分钟。

Go语言中内存逃逸分析是如何进行的?

Go的内存逃逸及分析:Go的内存逃逸涉及对内存的优化使用。分析内存逃逸前,需解决一些基础问题。我们的程序中的函数和局部变量默认存储在栈上。栈上存储的数据指针指向堆上的数据。

Go的内存逃逸及逃逸分析 Go的内存逃逸

分析内存逃逸之前要搞清楚一件事 我们编写的程序中的函数局部变量默认是存放在栈上的(补充一点堆上存储的数据的指针 是存放在栈上的 因为指针的大小是可以提前预知的 还有就是Go的基本类型也是存放在栈内的), 而其余的变量是存在堆上的, 栈是由操作系统层面控制 进行内存空间的释放 , 堆默认是程序控制的 像c c++ 是需要标明释放内存空间的位置 , 栈的运行速度远大于堆 . 拥有GC的高级语言回收的便是堆中的内容

  • Go编译器查看内存逃逸的结果 go build -gcflags=-m xxx.go
  • 发生内存逃逸的场景
  1. 函数返回局部变量是一个指针变量

# type User struct { Name string } func name(s string) *User { u := new(User) # 这个变量的类型是 *User 指针变量 u.Name = s return u } func main() { user := name("kuQi") fmt.Println(user) } # command-line-arguments ./main.go:9:6: can inline name ./main.go:18:14: inlining call to name ./main.go:19:13: inlining call to fmt.Println ./main.go:9:11: leaking param: s ./main.go:10:10: new(User) escapes to heap // 造成逃逸 ./main.go:18:14: new(User) escapes to heap // 造成逃逸 ./main.go:19:13: []interface {}{...} does not escape <autogenerated>:1: leaking param content: .this

2.interface的动态类型造成的内存逃逸

Go语言中内存逃逸分析是如何进行的?

// fmt.Println 接受的参数就是interface动态类型 编译器很难确定接收变量的类型 所有会将123这个变量逃逸到堆 func main() { fmt.Println(123) } # command-line-arguments ./main.go:16:6: can inline main ./main.go:20:13: inlining call to fmt.Println ./main.go:20:14: 123 escapes to heap ./main.go:20:13: []interface {}{...} does not escape <autogenerated>:1: leaking param content: .this

3.闭包函数产生的内存逃逸

// 因为函数也是一个指针类型 所以将匿名函数作为返回值时 也会产生内存逃逸 原理类似于 第一个 原因 func BiBao() func() string { return func() string { return "test" } } # command-line-arguments ./main.go:24:9: func literal escapes to heap: ./main.go:24:9: flow: ~r0 = &{storage for func literal}: ./main.go:24:9: from func literal (spill) at ./main.go:24:9 ./main.go:24:9: from return func literal (return) at ./main.go:24:2 ./main.go:24:9: func literal escapes to heap

4.变量大小无法确定 或 栈空间不足 引发内存逃逸

ulimit -a // ulimit -a 可以看到我们的栈空间是8192 -t: cpu time (seconds) unlimited -f: file size (blocks) unlimited -d: data seg size (kbytes) unlimited -s: stack size (kbytes) 8192 -c: core file size (blocks) 0 -v: address space (kbytes) unlimited -l: locked-in-memory size (kbytes) unlimited -u: processes 2784 -n: file descriptors 2560 // 超大切片超出栈空间 引发的内存逃逸 package main func main() { s := make([]int, 10000, 10000) // 创建一个超大切片 for index, _ := range s { s[index] = index } }