June's Studio.

Golang-内存分配&GC

字数统计: 636阅读时长: 2 min
2023/02/02

go性能观测 pprof

  • 你的程序时性能敏感型吗
  • GC带来的延迟影响到了你的程序性能吗
  • 你的程序有过多的内存分配吗

golang程序在启动时,会向系统申请一定区域的内存,分为栈(stack) 和堆(heap)

栈内存会随着函数的调用分配和回收;

堆内存由程序申请分配,由垃圾回收器(Garbage Collector)负责回收。

性能上,栈内存的使用和回收更迅速一些;

尽管Golang 的 GC 很高效,但也不可避免的会带来一些性能损耗。因此,Go 优先使用栈内存进行内存分配。在不得不将对象分配到堆上时,才将特定的对象放到堆中。

内存分配原则:

  • Sharing down typically stays on the stack 在调用方创建的变量或对象,通过参数的形式传递给被调用函数,这时,在调用方创建的内存空间通常在栈上。这种在调用方创建内存,在被调用方使用该内存的“内存共享”方式,称之为 Sharing down。
  • Sharing up typically escapes to the heap 在被调用函数内创建的对象,以指针的形式返回给调用方的情况下,通常,创建的内存空间在堆上。这种在被调用方创建,在调用方使用的“内存共享”方式,称之为 Sharing up。
  • Only the compiler knows 之所以上面两条原则都加了通常,因为具体的分配方式,是由编译器确定的,一些编译器后端优化,可能会突破这两个原则,因此,具体的分配逻辑,只有编译器(或开发编译器的人)知道。

go在判断一个变量或者对象是否需要逃逸到堆得操作时在编译阶段完成的

go build -gcflags=”-m -l”

总结:

1.因为栈比堆更高效,不需要 GC,因此 Go 会尽可能的将内存分配到栈上。

2.当分配到栈上可能引起非法内存访问等问题后,会使用堆,主要场景有:

  1. 当一个值可能在函数被调用后访问,这个值极有可能被分配到堆上。
  2. 当编译器检测到某个值过大,这个值会被分配到堆上。
  3. 当编译时,编译器不知道这个值的大小(slice、map…)这个值会被分配到堆上。

3.Sharing down typically stays on the stack

4.Sharing up typically escapes to the heap

5.Don’t guess, Only the compiler knows

CATALOG