Go逃逸分析

逃逸分析是一种确定指针动态范围的方法,简单来说就是分析在程序的哪些地方可以访问到某个指针。
Go是通过在编译器里做逃逸分析(escape analysis)来决定一个对象放栈上还是放堆上。
不逃逸的对象放栈上,随着函数退出后系统直接回收,不需要gc标记后再清除。
可能逃逸的放堆上,由系统GC来进行垃圾回收。

为什么要进行逃逸分析

  • 减少gc压力,栈上的变量,
  • 减少内存碎片的产生。
  • 减轻分配堆内存的开销,提高程序的运行速度。

golang 如何进行逃逸分析

$ go run -gcflags '-m -l' xxxx.go

这里的xxxx.go必须是包含main函数的。-m 输出逃逸分析的优化策略,-l禁用函数内联,减少干扰。

** 示例 **

cmd/main/main.go

package main

import (
	"os"
	"sync"
	"time"

	"github.com/cloudfstrife/bar"
)

func main() {
	bars := bar.MultiBar{}
	bar1 := bar.NewDefault()
	bar1.Title = "bar1"

	bar2 := bar.NewDefault()
	bar2.Title = "bar2"

	bar3 := bar.NewDefault()
	bar3.Title = "bar3"

	bars.Append(bar1)
	bars.Append(bar2)
	bars.Append(bar3)
	wg := sync.WaitGroup{}

	pro := func(b *bar.Bar, t time.Duration) {
		wg.Done()
		for i := 0; i <= 100; i++ {
			b.Percent = i
			time.Sleep(t)
		}
	}
	wg.Add(1)
	go pro(bar1, 100*time.Millisecond)

	wg.Add(1)
	go pro(bar2, 200*time.Millisecond)

	wg.Add(1)
	go pro(bar3, 500*time.Millisecond)

	wg.Add(1)
	go func() {
		defer wg.Done()
		defer bars.Show(os.Stdout)
		for {
			bars.Show(os.Stdout)
			time.Sleep(100 * time.Millisecond)
			if bar1.Percent == 100 && bar2.Percent == 100 && bar3.Percent == 100 {
				break
			}
		}
	}()
	wg.Wait()
}
$ go  run -gcflags '-m -l' cmd/main/main.go
# command-line-arguments
cmd\main\main.go:34:4: wg escapes to heap
cmd\main\main.go:25:2: moved to heap: wg
cmd\main\main.go:27:9: func literal escapes to heap
cmd\main\main.go:27:9: func literal escapes to heap
cmd\main\main.go:28:3: &wg escapes to heap
cmd\main\main.go:37:4: wg escapes to heap
cmd\main\main.go:40:4: wg escapes to heap
cmd\main\main.go:43:4: wg escapes to heap
cmd\main\main.go:44:5: func literal escapes to heap
cmd\main\main.go:44:5: func literal escapes to heap
cmd\main\main.go:45:9: &wg escapes to heap
cmd\main\main.go:46:9: &bars escapes to heap
cmd\main\main.go:12:2: moved to heap: bars
cmd\main\main.go:55:4: wg escapes to heap
cmd\main\main.go:28:5: wg escapes to heap
cmd\main\main.go:28:3: leaking closure reference wg
cmd\main\main.go:45:11: wg escapes to heap
cmd\main\main.go:45:9: leaking closure reference wg
cmd\main\main.go:46:13: bars escapes to heap
cmd\main\main.go:46:9: leaking closure reference bars
cmd\main\main.go:46:18: os.Stdout escapes to heap
cmd\main\main.go:48:8: bars escapes to heap
cmd\main\main.go:46:9: leaking closure reference bars
cmd\main\main.go:48:13: os.Stdout escapes to heap
cmd\main\main.go:22:6: main bars does not escape
cmd\main\main.go:23:6: main bars does not escape
cmd\main\main.go:24:6: main bars does not escape
cmd\main\main.go:27:14: main.func1 b does not escape
<autogenerated>:1: os.(*File).close .this does not escape
<autogenerated>:1: os.(*File).isdir .this does not escape