go内存逃逸

go内存分配与逃逸分析

内存管理主要包括俩个动作:分配与释放

逃逸分析是服务与内存分配的

而内存的释放由GC负责

在go语言中,栈的内存是由编译器自动进行分配和释放的,栈区往往存储着函数参数,局部变量和调用函数帧,它们随着函数的创建而分配,随着函数的退出而销毁

go应用程序运行时,每个goroutine都维护着一个自己的栈区,这个栈区只能自己使用而不能被其它goroutine使用。栈是调用栈(call stack)的简称。一个栈通常又包含了许多栈帧,它描述的是函数之间的调用关系

与栈不同的是,堆区的内存一般是由编译器和工程师自己共同进行分配管理的,交给Runtime GC来释放。在堆上分配时,必须找到一块足够大的内存来存放新的变量数据。后续释放时,垃圾回收期扫描堆空间寻找不再被使用的对象

逃逸分析

相比于把内存分配到堆上,分配到栈中优势更加明显

Go编译器会尽可能将变量分配到栈上

但是在函数返回后无法证明变量未被引用,则该变量将被分配到堆上,该变量不随函数栈的回收而回收,以此来避免悬挂指针的问题

如果变量占用内存大也会放入堆上

Go是如何确定内存是分配到栈上还是堆上呢?

答案就是:内存逃逸

编译器通过逃逸分析技术来选择堆或者栈,逃逸分析的基本思想如下:检查变量的生命周期是否完全可知的,如果通过检查,则在栈上分配,否则就是所谓逃逸,必须在堆上进行分配

逃逸分析原则

Go语言虽然没有明确说明逃逸分析原则,但有以下几点准则是可以参考的:

  • 不同于JAVA JVM的运行时逃逸分析,Go的逃逸分析是在编译期完成的:编译期无法确定的参数类型必定放到堆中
  • 如果变量在函数外部存在引用,则必定放在堆中
  • 如果变量占用内存较大时,则优先放到堆中
  • 如果变量在函数外部没有引用,则优先放到栈中
  • 变量大小无法确定时也会发生内存逃逸
comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计