Golang-GC相关问题

Go中GC流程

Go1.14版本以STW为界限,可以将GC划分为五个阶段:

  • GCMark 标记准备阶段,为并发标记做准备工作,启动写屏障
  • STWGCMark扫描标记阶段,与赋值器并发执行,写屏障开启并发
  • GCMarkTermination 标记终止阶段,保证一个周期内标记任务完成,停止写屏障
  • GCoff 内存清扫阶段,将需要回收的内存归还到堆中,写屏障关闭GCoff
  • 内存归还阶段,将过多的内存归还给操作系统,写屏障关闭。

GC触发机制

  • 主动触发:调用runtime.GC
  • 被动触发:
    1. 使用系统监控,该触发条件由runtime.forcegcperiod变量控制,默认为2分钟。当超过两分钟没有产生任何GC时,强制触发GC。
    2. 使用步调(Pacing)算法,其核心思想是控制内存增长的比例。如Go的GC 是一种比例GC,下一次GC结束时的堆大小和上一次GC存活堆大小成比例.

GC调优

通过go tool pprofgo tool trace等工具

  • 控制内存分配的速度,限制Goroutine的数量,从而提高赋值器对CPU的利用率。
  • 减少并复用内存,例如使用sync.Pool来复用需要频繁创建临时对象,例如,提前分配足够的内存来降低多余的拷贝。
  • 需要时,增大GOGC的值,降低GC的运行频率。

Go的内存模型中为什么小对象多了会引发垃圾回收(GC)压力?

  1. 内存分配和回收的开销:Go语言的垃圾回收器是基于标记-清除算法的,它需要遍历内存中的对象来标记和回收不再使用的对象。对于小对象,特别是大量小对象的分配和回收,会导致频繁的GC操作。这是因为小对象的数量多,回收器需要不断扫描和标记这些对象,增加了GC的开销。

  2. 内存碎片问题:分配和回收小对象可能会导致内存碎片问题。当小对象被分配和回收后,它们的内存空间可能会在堆上留下一些碎片,这些碎片可能无法有效地被重复利用。随着时间的推移,内存中可能会出现许多不同大小的碎片,最终导致了内存浪费和GC的效率下降。

  3. 垃圾回收频率增加:由于小对象的分配和回收频繁,垃圾回收可能会更频繁地运行。这会导致应用程序的吞吐量下降,因为垃圾回收会占用CPU时间,导致应用程序的暂停时间增加。

为了减少小对象引起的垃圾回收压力,可以采取以下一些策略:

  1. 对象池(Object Pooling):对象池是一种技术,它允许重复使用已分配的对象,而不是频繁地分配和回收它们。这可以减少GC的频率和内存碎片。

  2. 避免频繁分配和回收:尽量避免频繁地分配和回收小对象,特别是在循环中。可以考虑重用对象或者使用更大的缓冲区,减少分配次数。

  3. 调整堆大小和GC参数:通过调整Go程序的堆大小和GC参数,可以尝试减少GC的频率。可以使用GODEBUG环境变量来监控GC的行为,并进行适当的调整。

  4. 使用内存分配分析工具:Go提供了一些内存分配分析工具,如pprof,可以帮助你识别内存分配和垃圾回收的瓶颈,并优化你的代码。

总之,小对象的频繁分配和回收可能会增加垃圾回收的压力,因此在编写Go代码时,需要考虑如何优化内存使用,以减少GC的频率和内存碎片问题。

是小柒鸭
是小柒鸭
佛系·猫奴·程序媛

在无聊的时间里就从事学习。 —— 亚伯拉罕·林肯

相关