逃逸分析主要是进行内存优化,go没有直接操作内存的方法,采用自动gc,了解内存分配机制,可以写 高质量的代码;
go有两种方式分配内存,堆和栈,堆分配昂贵,栈分配廉价,所有内存优先栈分配,但栈分配要求变量生命周期和内存足迹(和一个变量相关的所有内存块)在编译时确定;
逃逸分析是用于堆和栈分配进行选择,通过在编译时期做gc,编译器追踪变量在代码块的作用域,判断变量在整个运行周期是否在运行时完全可知,通过校验可以在栈上分配;否则逃逸到堆上;
go build -gcflags '-m' 可以显示变量逃逸分析;
变量逃逸到堆上情况:
1.局部函数创建内部对象,返回其指针;
2.在slice上存储指针或带有指针的值;slice扩容会基于运行时扩容,会逃逸堆上分配;
3.map的value存指针会逃逸;
4.发送指针或带有指针的值到channel会逃逸;
5.在interface上调用方法会逃逸,因为interface是运行时动态调度,只有运行时才知道;所以在服务调用多的接口少使用interface;
6.调用逃逸函数会造成逃逸,如println;
一般认为值拷贝耗资源,可以用一个指针代替,但很多时候使用值拷贝是节省资源的;因为:
1.编译器在解除指针会做检查;
2.无指针的对象,垃圾回收器直接略过这段内存;
3.值拷贝具有较好的局部引用,函数内所有值会在栈上分配,会使得变量数据在cpu的cache热度更高;
内存优化:
1.slice、map预分配内存
2.函数尽量使用值非指针
3.使用锁时,用原子化操作,用sync/atomic包
4.使用不带缓存的channel