浅析golang的内存逃逸

内存逃逸

内存逃逸的含义

  • 是指从栈上分配变为从堆上分配,go在编译的时候会进行逃逸分析,来决定一个对象是放栈上还是放堆上,不逃逸的对象放栈上,可能逃逸的放堆上。

逃逸场景

  • 指针逃逸

    go返回局部变量指针,在方法内将局部变量指针返回,例如:

    package main
    
    type testStr struct {
        test string
    }
    
    func newTestStr(v string) *testStr {
        t := new(testStr)
        t.test = v
    
        return t
    }
    
    func main() {
        newTestStr("test")
    }
    

    运行命令 go build -gcflags=-m

    然后看执行结果:

    .\testescapeanalysis.go:7:6: can inline newTestStr
    .\testescapeanalysis.go:14:6: can inline main
    .\testescapeanalysis.go:15:12: inlining call to newTestStr
    .\testescapeanalysis.go:7:17: leaking param: v
    .\testescapeanalysis.go:8:10: new(testStr) escapes to heap
    .\testescapeanalysis.go:15:12: new(testStr) does not escape
    

    可以看到第五行出现escapes to heap

  • 栈空间不足逃逸

    空间开辟过大,在编译期间,如果知道自己的size,那么放入栈中,但是append的时候,可能不知道具体扩容数量,这个时候放入堆中,比如:

      package main
    
      func testSlice() {
          s := make([]int, 10000, 10000)
    
          for i, _ := range s {
              s[i] = i
          }
      }
    
      func main() {
          testSlice()
      }
    

    然后看执行结果:

      # command-line-arguments
      .\testescapeanalysis.go:11:6: can inline main
      .\testescapeanalysis.go:4:11: make([]int, 10000, 10000) escapes to heap
    

    当空间分配过大,出现内存逃逸

  • interface类型多态的时候

    编译期间很难确定参数具体类型,也会产生逃逸,比如:

      package main
      import "fmt"
    
      type Animal interface {
          voice()
      }
    
      type Cat struct{}
      func (cat Cat) voice() {
          fmt.Println("cat voice")
      }
    
      type Dog struct{}
      func (dog Dog) voice() {
          fmt.Println("cat voice")
      }
    
      func main() {
          var animal Animal
          animal = Cat{}
          animal.voice() // 调用方法时,发生逃逸,因为方法是动态分配的
          animal = Dog{}
          animal.voice()
      }
    

    然后看执行结果:

      # command-line-arguments
      .\testescapeanalysis.go:11:6: can inline Cat.voice
      .\testescapeanalysis.go:12:13: inlining call to fmt.Println
      .\testescapeanalysis.go:17:6: can inline Dog.voice
      .\testescapeanalysis.go:18:13: inlining call to fmt.Println
      .\testescapeanalysis.go:12:14: "cat voice" escapes to heap
      .\testescapeanalysis.go:12:13: []interface {} literal does not escape
      .\testescapeanalysis.go:18:14: "cat voice" escapes to heap
      .\testescapeanalysis.go:18:13: []interface {} literal does not escape
      .\testescapeanalysis.go:23:9: Cat literal escapes to heap
      .\testescapeanalysis.go:25:9: Dog literal escapes to heap
    
  • 闭包引用包外的值

    由于被闭包引用,所以会放到堆上

  • chan中发送数据的指针或者包含指针的值

    编译起并不知道何时释放,所以也是放到堆中

  • slice、map中存储指针或者包含指针的值

    假使slice是在栈上,但是存储的值也会放到堆中

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值