likes
comments
collection
share

Golang内存管理—垃圾收集器:栈对象处理

作者站长头像
站长
· 阅读数 13

0. 简介

上一篇博客,我们基本介绍了GolangGC原理,这里我们触及一下GC过程中栈对象的处理。其实问题的起因在于我最开始对栈对象在GC时的生存周期的误解,最初我认为:栈对象会在栈返回后才会自动消失!但是在Golang基础数据结构—字符串unsafeStringToBytes测试时,我通过-gcflags='-m'发现字符串s并没有逃逸到堆上,建立在我一上认知,我觉得它不会被GC呀,但是测试结果打了我的脸。所以后续我就对GolangGC时对栈对象的处理进行了一番探究。

1. 栈对象跟踪

栈对象是在栈上能够被寻址的对象,其一定在栈上有地址。所以就被叫做栈对象。因为并不是所有的变量都会存储在栈上,例如存储在寄存器中的变量就是不能被寻址的。

具体说明可以参考Golang源码:src/runtime/mgcstack.go。我这里就不完全翻译其说明了,只说一下我理解的栈跟踪步骤,如果有问题,还麻烦大家指出。

1.1 栈对象活性分析

Go的编译器编译代码的最后一步——生产机器码时,会完成其重要的工作——栈布局(stack frame layout),其将栈偏移位置分配给局部变量,以及指针活性分析(pointer liveness analysis),后者计算每个垃圾回收安全点上的哪些栈指针仍然是存活的。具体参考Go 编译器介绍

也就是前面说过的unsafeStringToBytes函数中sGC点已经不存活了。

// 不安全的转换方法
func unsafeStringToBytes(s string) []byte {
   sh := (*reflect.StringHeader)(unsafe.Pointer(&s))
   sliceHeader := &reflect.SliceHeader{
      Data: sh.Data,
      Len:  sh.Len,
      Cap:  sh.Len,
   }

   runtime.GC()
   time.Sleep(1 * time.Nanosecond)

   b := *(*[]byte)(unsafe.Pointer(sliceHeader))
   return b
}

而如果我们在return b之前加上runtime.KeepAlive(s)后,就可以避免sGC掉,其实所谓runtime.KeepAlive所做的事情就是使一个变量”存活“到其所在的位置被执行,具体做法是Go编译器会设置一个名为 OpKeepAlive 的静态单赋值(SSA),然后剩余的编译就会知道将这个变量的存活期保证到使用了 runtime.KeepAlive() 的时刻。

1.2 栈跟踪

单纯的栈对象活性分析并不能满足所有的需求,比如该栈对象的指针指向其他非存活栈对象,那么很可能会漏掉,所以就需要栈跟踪来保证找到剩下的需要存活的对象了。

比如以下的栈:

+----------+
| foo()    |
| +------+ |
| |  A   | | <---\
| +------+ |     |
|          |     |
| +------+ |     |
| |  B   | |     |
| +------+ |     |
|          |     |
+----------+     |
| bar()    |     |
| +------+ |     |
| |  C   | | <-\ |
| +----|-+ |   | |
|      |   |   | |
| +----v-+ |   | |
| |  D  ---------/
| +------+ |   |
|          |   |
+----------+   |
| baz()    |   |
| +------+ |   |
| |  E  -------/
| +------+ |
|      ^   |
| F: --/   |
|          |
+----------+
  • foo()调用bar()bar()调用baz(),每个方法再在栈上都体现出一段帧;
  • foo()中有栈对象AB
  • bar()中有栈对象CDC指向DDA
  • baz()中有栈对象E,指向C,还有个局部变量F指向E

从存活的局部变量F开始,经过扫描,最终会将ECDA扫描到,但是B不是被扫描到,因为没有指向其的存活指针,同理,B指向堆的指针(如果有的话)也就不被认为是存活的。

其设计参考:docs.google.com/document/d/…

转载自:https://juejin.cn/post/7239542388603600951
评论
请登录