Go进阶之逃逸分析

22 阅读2分钟

逃逸分析是指由编译器决定内存分配的位置.不需要程序员指定.在函数中申请一个新

的对象.

1).如果分配在栈中.则函数执行结束后可自动将内存回收.

2).如果分配在堆中.则函数执行结束后可交给GC(垃圾回收)处理.


1.逃逸策略:

在函数中申请新对象.编译器会根据该对象是否被函数外部引用来决定是否逃逸.

如果函数外部没有引用.则优先放到栈中.

如果函数存在外部引用.则必定放到对堆中.

注:对于仅在函数内部使用的变量.也有可能放到堆中.比如内存过大超过了栈的存储能力.

2.逃逸场景:

指针逃逸:

示例代码:

package main

import (
    _ "gomodule/pubsub"
)

type student struct {
    name string
    age  int
}

func StudentRegister(name string, age int) *student {
    //局部变量逃逸到堆中.
    s := new(student)
    s.name = name
    s.age = age
    return s
}

func main() {
    StudentRegister("toney", 18)
}

函数StudentRegister()内部的s为局部变量.其值通过函数返回值返回.s本身为一个

指针.其指向的内存地址不会是栈而是堆.

通过编译参数-gcflags=-m编译如下.

escapes to heap 表示发生了逃逸现象.

栈空间不足逃逸:

package main

import (
    _ "gomodule/pubsub"
)

func Slice() {
    slice := make([]int, 10000, 10000)
    for i := range slice {
       slice[i] = i
    }
}

func main() {
    Slice()
}

通过编译参数-gcflags=-m编译如下.

实际上当栈空间不足以存放当前对象或无法判断当前切片长度时会将对象放到堆中.


动态类型逃逸:

很多函数类型为interface类型.编译期间很难确定类型.也会产生逃逸.示例如下.

package main

import (
    "fmt"
    _ "gomodule/pubsub"
)

func main() {
    s := "test escapes to heap"
    fmt.Println(s)
}

3.3小结:

栈上分配内存比在堆中分配内存有更高的效率.

栈上分配内存不需要GC处理.

堆上分配内存使用完毕会交给GC处理.

逃逸分析的目的是决定分配地址是在栈还是堆.

逃逸分析在编译阶段完成.

追风筝的人.





如果大家喜欢我的分享的话.可以关注我的微信公众号

念何架构之路