一、逃逸分析
逃逸分析把变量合理地分配到它该去的地方,“找准自己的位置”,即使是用new函数申请到的内存,如果编译器发现这块内存在退出函数后就没有使用了,那就分配到栈上,毕竟栈上的内存分配比堆上快很多;反之,即使表面上只是一个普通的变量,但是经过编译器的逃逸分析后发现,在函数之外还有其他的地方在引用,那就分配到堆上,真正地做到 “按需分配”
内存逃逸的五种情况:
1. 发送指针的指针或值包含了指针到 channel 中,由于在编译阶段⽆法确定其作⽤域与传递的路径,所以⼀般都会逃逸到堆上分配。
2. slices 中的值是指针的指针或包含指针字段。⼀个例⼦是类似 []*string 的类型。这总是导致 slice 的逃逸。即使切⽚的底层存储数组仍可能位于堆栈上,数据的引⽤也会转移到堆中。
3. slice 由于 append 操作超出其容量,因此会导致 slice 重新分配。这种情况下,由于在编译时 slice 的初始⼤⼩的已知情况下,将会在栈上分配。如果 slice 的底层存储必须基于仅在运⾏时数据进⾏扩展,则它将分配在堆上。
4. 调⽤接⼝类型的⽅法。接⼝类型的⽅法调⽤是动态调度,实际使⽤的具体实现只能在运⾏时确定。考虑⼀个接⼝类型为 io.Reader 的变量 r。对 r.Read(b) 的调⽤将导致 r 的值和字节⽚b的后续转义并因此分配到堆上。
5. 尽管能够符合分配到栈的场景,但是其⼤⼩不能够在在编译时候确定的情况,也会分配到堆上.