Go的GC垃圾回收

Go语言的GC垃圾回收

GC
垃圾回收GC是一种自动管理内存的机制,垃圾回收器会尝试回收程序不再使用的对象和占用的内存
在程序中设置GC的触发频率
debug.SetGCPercent

垃圾回收算法:

  • 1.引用计数
  • 2.标记-清除 Go采用三色标记法
  • 3.分代收集
引用计数:

对每个对象维护一个引用计数,当引用该对象的对象被销毁时,引用计数减1,当引用计数器为0时回收该对象
优点:对象可以很快被回收
缺点:不能很好的处理循环引用,而且实时的维护引用计数也有一定的代价
代表语言:php,python

标记-清除:

从根变量开始遍历所有引用的对象,引用的对象标记为”被引用”,没有被标记的变量被回收
优点:解决引用计数的缺点,不能很好的处理循环引用,而且实时的维护引用计数也有一定的代价的缺点
缺点:暂停程序的执行
代表语言:Go (三色标记法)

分代收集

按照对象生命周期的长短划分不同的代空间,生命周期长的放入老年代,而短的放入新生代,不同代有不同的回收算法和回收频率
优点:收回性能好
缺点:算法复杂
代表语言:java

Go的垃圾回收

Go垃圾回收的原理是,标记出哪些内存还在使用中,(即被引用到),哪些内存不在使用了(即未被引用),把未被引用的内存回收,以供后续内存分配时再使用
缺点就是,不是实时的回收内存,而是暂停程序的执行去处理内存回收

三色标记法

这里的三色是对应了垃圾回收过程中对象的三种状态
1.灰色:对象还在标记队列中等待
2.黑色:对象已经被标记(该对象不会在本次GC中被清理)
3.白色:对象未被标记(该对象会在本次GC中被清理)

Go的STW

Go中的STW(Stop The World)就是停止所有的goroutine,专心做垃圾回收,待垃圾回收结束后,再恢复goroutine,STW的长短直接影响了程序的性能

垃圾回收优化

1.写屏障
就是让goroutine与GC同时运行的手段,GC过程中新分配的内存会被立即标记,即本轮不回收,下次GC时再确定

2.补助GC
使用goroutine参与一部分的GC工作来提高性能

垃圾回收的触发时机

1.内存分配量达到阈值触发GC
每次内存分配时都会检查当前内存分配量是否已达到阈值,如果达到阈值则立即触发GC
阈值 = 上次GC内存分配量 X 内存增长率
内存增长率由环境变量GOGC控制,默认为100,即每当内存扩大一倍时启动GC

2.定期触发GC
默认情况下,最长两分钟触发一次GC

3.手动触发
使用 runtime.GC() 来手动触发GC
主要用于GC的性能测试和统计

逃逸分析
是指由编译器决定内存分配的位置,不需要程序员指定

在函数中申请一个新的对象:
如果分配在栈中,则函数执行结束后,可自动将内存回收
如果分配在堆中,则函数执行结束后可交给GC(垃圾回收)处理

1.逃逸策略
在函数中申请新的对象时,编辑器会根据该对象是否被函数外部引用来决定是否逃逸:
如果函数外部没有引用,则优先放在栈中
如果函数外部存在引用,则必定存放在堆中

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

使用interface类型存在逃逸的可能(动态类型逃逸)
闭包引用对象逃逸