【golang】变量的stack/heap分配与逃逸分析不解之情
2020-04-15 本文已影响0人
dongzd
堆栈定义
- 栈 stack:由操作系统自动释放,存放函数的参数值、局部变量等,更新速度快。
- 堆 heap:一般由程序员释放,在Golang中自动垃圾回收gc掉,存放全局变量、共享变量等。
golang 参数传递重点
- 使用值传递,该值存放在stack上,当return时候会自动释放。
- 使用引用传递,该值存放在heap上,需要gc。
使用引用传递,因为复制的是一份地址,减少大的结构体传递的内存占用。但因为存放在heap上需要垃圾回收掉,运行速度要比值传递慢。所以出来共享传递参数外,尽量值传递
golang 变量函数中分配位置
go语言编译器会自动决定把一个变量放在栈还是放在堆,编译器会做逃逸分析(escape analysis),当发现变量的作用域没有跑出函数范围,就可以在栈上,反之则必须分配在堆。
在c/c++,一般通过new(动态申请)出来的变量,都会存放在heap上,而对于golang则是:
- Golang中一个函数内局部变量,不管是不是动态new出来的,它会被分配在堆还是栈,是由编译器做逃逸分析之后做出的决定。
- 逃逸分析,把变量合理地分配到合适的位置。即使你在函数里面是用new申请的内存,在函数退出后发现没有用了,那么就把你放到栈上,栈的内存分配比堆快很多;反之,即使在函数内部申明普通变量var,但进过逃逸分析发现退出函数后还被其他地方引用(就是将函数内部申明的变量地址return出),那么就分配到堆上。
分配到堆与分配到栈上性能差异
- 如果变量分配到堆上,堆不像栈可以自动清理。它会引起go频繁的进行垃圾回收,而垃圾回收会占用大量的系统开销(占cpu容量的25%)。
- 栈和堆比,堆适合不知大小的内存分配,为此付出分配速度较慢,形成内存碎片。栈分配内存非常快。
逃逸分析作用
做逃逸分析为了尽量把不需要分配到堆上的变量,分配到栈上,堆上变量少了,减轻内存分配开销,减少gc压力,提高运行性能