golang GC机制

Golang自1.5版本开始引入三色GC,多次改进,GC停顿时间降低到1ms。

一:GC的触发

GC的触发条件有以下几种:

  • gcTriggerAlways:强制触发GC
  • gcTriggerHeap:当前分配的内存达到一定值就触发GC
  • gcTriggerTime:当一定时间没有执行过GC触发
  • gcTriggerCycle:要求启动新一轮的GC,已启动则跳过,手动触发GC的runtime.GC()会使用这个条件
    其中gcTriggerHeap和gcTriggerTime这两个条件是自然触发的。
    gcTriggerHeap的判断依据为:
memstats.heap_live >= memstats.gc_trigger //heap_live is the number of bytes considered live by the GC
其中memstats.gc_trigger的计算公式是:
trigger = unit64(float64(memstats.heap_marked)*(1+triggerRatio))//heap_marked is the number of bytes marked by the previous GC
tiggerRatio 与goalGrowthRatio正相关
goalGrowthRatio = float64(gcpercent)/100

公式中的goalGrowthRatio“目标Heap增长率”通过设置环境变量GOGC(gcpercent)调整,默认值为100。
gcTriggerTime的判断依据为:

t.now - lastgc > forcegcperiod

其中forcegcperiod的定义是2分钟,也就是2分钟没有执行GC就会强制触发。

二:如何进行GC优化

2.1:硬性参数GOGC
比如当前程序使用4M堆内存,即memstats.heap_marked内存为4M,当程序占用的内存上升到memstats.heap_marked*(1+GOGC/100)=8M时候,gc就会被触发,开始进行相关的gc操作。
如何对GOGC的参数进行设置,要根据生产情况中的实际场景来定。增加它的值可以减少GC触发但需保证内存足够大。如果你的内存少,只能更频繁的GC以节省内存,那么降低GOGC值。设置GOGC=off可以彻底关掉GC
2.2:减少对象分配
内存复用,减少对象申请。下面的样例代码中实现内存复用,其关键是一个缓存的管道buffer,可存储5个字节数组,当程序需要一个字节数组时候,优先使用select从缓存的管道中去取。最终内存池中的内存和从操作系统请求的内存很接近,堆中只有很少量的未使用内存最终返还给操作系统。

package main
import (
    "fmt"
    "math/rand"
    "runtime"
    "time"
)
func makeBuffer() []byte {
   
    return make([]byte, rand.Intn(5000000)+5000000)
}
func main() {
   
    pool := make([][]byte, 20)
    buffer := make(chan []byte, 5)
    var

你可能感兴趣的:(golang)