> For the complete documentation index, see [llms.txt](https://plainchant.gitbook.io/plainchant/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://plainchant.gitbook.io/plainchant/golang/golang-ji-chu/go-tao-yi-fen-xi.md).

# go逃逸分析

## 堆和栈

在go语言中，我们很少关心堆或者栈，因为go语言会根据变量的使用情况做分析，编译时就帮我们对变量的空间分配做了优化。 在C语言中，则需要格外关心堆栈情况，以及全局静态变量空间。 C语言的全局变量会放到全局变量地址空间，局部变量会放到栈上，如果用malloc分配的内存，则会放在堆上，编程时需注意空间的分配和回收避免造成内存泄露。

而在go语言中，逃逸的变量会被分配到堆上，没有发生逃逸的对象则会分配到栈上。也就是说，golang中，不再使用关键字区分堆栈，而是根据逃逸分析自动分配。 go语言之所以也要关心堆栈，则是和垃圾回收，内存效率相关，一个好的程序可以节省更多的内存空间，实现更好的性能。

* 减少gc压力，栈上的变量，随着函数退出后系统直接回收，不需要gc标记后再清除。
* 减少内存碎片的产生。
* 减轻分配堆内存的开销，提高程序的运行速度。

## 调试逃逸分析

在Go中通过逃逸分析日志来确定变量是否逃逸，开启逃逸分析日志：

```
go run -gcflags '-m -l' main.go
```

* -m 会打印出逃逸分析的优化策略，实际上最多总共可以用 4 个 -m，但是信息量较大，一般用 1 个就可以了。
* -l 会禁用函数内联，在这里禁用掉内联能更好的观察逃逸情况，减少干扰。

## 编译逃逸分析

所谓逃逸分析（Escape analysis）是指由编译器决定内存分配的位置，不需要程序员指定。 在函数中申请一个新的对象：

* 如果分配 在栈中，则函数执行结束可自动将内存回收；
* 如果分配在堆中，则函数执行结束可交给GC（垃圾回收）处理;

注意，对于函数外部没有引用的对象，也有可能放到堆中，比如内存过大超过栈的存储能力。

## 会逃逸的情况

* 返回局部变量指针
* 栈空间不足逃逸（空间开辟过大）
* 动态类型逃逸（不确定长度大小）
* 闭包引用对象逃逸

## 逃逸总结

* 栈上分配内存比在堆中分配内存有更高的效率
* 栈上分配的内存不需要GC处理
* 堆上分配的内存使用完毕会交给GC处理
* 逃逸分析目的是决定内分配地址是栈还是堆
* 逃逸分析在编译阶段完成

函数传递指针真的比传值效率高吗？ 我们知道传递指针可以减少底层值的拷贝，可以提高效率，但是如果拷贝的数据量小，由于指针传递会产生逃逸，可能会使用堆，也可能会增加GC的负担，所以传递指针不一定是高效的。
