go语言中也会存在c++语言的内存泄漏和指针逃逸,所以go语言采用了逃逸分析来解决这种危险情况。
内存泄漏:如果使用C语言中的malloc动态分配内存,但却使用后忘记释放该内存,那么该内存就会发生泄漏,即原内存空间变小该内存不能被使用。
指针逃逸:把一个对象的指针被多个方法或者线程引用叫做这个指针发生了逃逸。
逃逸分析前提要知道栈和堆的概念。
栈:与数据结构中的栈相同却有不同,数据结构中的栈是一种数据存储了逻辑方式,这种方式要求先入后出。而操作系统的栈是指操作系统自动为程序分配的一部分内存,这部分内存用来存储局部变量或者保存函数调用栈。
堆:与栈相区别,堆是程序员自己向操作系统申请的一部分内存空间,用来满足其特别需要,程序员可以确定该内存的大小。
如果在一个函数内部创造一局部变量,又把该局部变量的指针作为返回值,那么程序会崩溃。因为局部变量在函数栈中,函数运行完毕会销毁其栈空间。如果把这个变量用new的方式创建则可以在函数返回后继续使用。因为变量是在堆内存中,函数运行后并不会销毁。
但是这块堆内存没有人保证它不会被忘记释放,即导致内存泄漏。为了解决内存泄漏的问题,很多语言都会采用一个GC的组件,用来回收一些没用的内存空间。
而逃逸分析就是尽量把内存分配到栈上,减少分配到堆上,减少GC压力,提高程序运行速度。
逃逸分析:根据判断变量在函数外是否被其他函数使用来确定把该变量分配到栈上还是堆上。若在函数外无使用,则分配到栈上,否则分配到堆上。
逃逸分析的补充:
- 如果定义很大数组,超过栈内存也会使用堆内存。
- 对于interface此类类型不确定的变量,也会发生逃逸。如fmt.Println(interface{})
对于go语言栈和堆的补充:
- go语言也是应用程序,可以以自己编写的程序来理解,操作系统自动分配go语言的栈空间被要运行go语言的自身的组件所消耗如runtime、GC。而我们写go程序时所使用的栈和堆是go语言所创建堆空间的逻辑划分,这类思想在计算机中很常用。由此带来的好处是我们使用的栈很大,一般语言的栈1MB,而go程序的栈可以达到1GB
- go语言为了防止栈的内存碎片化,会适当进行深拷贝,即把数据拷贝到另一处内存区域中。所以go语言一般不能指针运算。