Go 垃圾回收

简介: Go 垃圾回收

Garbage Collection( GC )也就是垃圾回收到底是什么?内存空间是有限的,诸如变量等需要分配内存才能存储数据,而当这个变量不再使用的时候就需要释放它占用的内存,这就是垃圾回收。


Go 的垃圾回收运行在后台的守护线程中,会自动追踪检查对象的使用情况,然后回收不再使用的空间,我们一般并不会也不需要直接接触到它。



01


GC 模型


Go 使用的是 Mark-Sweep(标记-清除)方式,其具体的垃圾回收算法一直都在调整优化,本文并不打算去介绍这些算法,而是从一个整体的角度去描述 GC 的过程。


Collection 可以分为三个阶段:

  • Mark Setup - STW
  • Marking - Concurrent
  • Mark Termination - STW


STW 是 Stop The World 的缩写,意思是 GC 的时候会暂停其它所有任务,正是如此才导致了延迟的存在。


1、Mark Setup - STW


垃圾回收开始,首先需要开启 Write Barrier(写屏障),为此所有应用程序 goroutine 必须暂停,这个过程通常很快,平均 10 - 30 微秒。


假设应用程序当前运行了四个 goroutine :


我们需要等待所有 goroutine 暂停,而暂停操作是需要出现一次函数调用才能完成,如果某个 goroutine 始终没有发生函数调用(比如一直在执行某个非常长的循环操作)而其它 goroutine 却完成了会怎样,就会如下图:然而,必须所有的 goroutine 全部都暂停,垃圾回收才能继续进行,不然就会卡在这里一直等待,结果就是延迟越来越高。这个问题官方团队计划将在 1.14 版本通过优先策略进行优化。


一旦这一阶段完成,Write Barrier(写屏障)开启,就会进入下一阶段。


2、Marking - Concurrent


进行标记,Concurrent 表示这个过程是并发进行的,不会 STW ,GC 会先征用 25% 的 CPU 资源,如下图:GC 占用了 P1 逻辑处理器,而其它 goroutine 正常的并发运行。


但是,有些时候 GC 的任务特别繁重,需要更多的资源,这个时候怎么办?开启 Mark Assit 协助工作,如下图中的 MA :


标记完成,进行下一个阶段。


3、Mark Termination - STW


标记终止。关闭 Write Barrier(写屏障),执行各种清理任务,然后计算下一次 GC 的目标,这个阶段也是需要 STW 的,平均 60 - 90 微秒:


一旦 GC 完成,goroutine 继续执行:


Sweeping - Concurrent


Sweeping(清除)需要等待 collection 完成之后,回收被标记为未使用的值的内存,这个过程发生在应用程序 goroutine 尝试给新值分配内存空间时,Sweeping 的延迟将会增加内存分配的成本。



02


延迟优化


虽然 Go 的 GC 很优秀,但正如前文所述,GC 的延迟还是会拖累应用程序的,那么我们在应用程序中可以进行怎么的优化呢?答案是降低内存的压力即分配内存的频率,比如使用 slice 时,尽量避免因为容量不够了而导致分配更多的内存的频率( Go 开发十种常犯错误 )。


如何调试我们的程序去发现需要优化的地方?


1、开启 gotrace 追踪各种指标:

GODEBUG=gctrace=1

通过指标数据可以看到各个过程及耗时情况,比如:


2、使用 pprof


具体用法请自行参考其它资料。

---------

参考:https://www.ardanlabs.com/blog/2018/12/garbage-collection-in-go-part1-semantics.html
https://www.ardanlabs.com/blog/2019/05/garbage-collection-in-go-part2-gctraces.html
https://www.ardanlabs.com/blog/2019/07/garbage-collection-in-go-part3-gcpacing.html

目录
相关文章
|
7月前
|
算法 Java Go
Go vs Java:内存管理与垃圾回收机制对比
对比了Go和Java的内存管理与垃圾回收机制。Java依赖JVM自动管理内存,使用堆栈内存并采用多种垃圾回收算法,如标记-清除和分代收集。Go则提供更多的手动控制,内存分配与释放由分配器和垃圾回收器协同完成,使用三色标记算法并发回收。示例展示了Java中对象自动创建和销毁,而Go中开发者需注意内存泄漏。选择语言应根据项目需求和技术栈来决定。
|
4月前
|
算法 安全 Java
|
7月前
|
缓存 算法 安全
浅谈go垃圾回收与竞争检测
【5月更文挑战第16天】Go语言的运行时聚焦于垃圾回收(GC)和并发特性。GC通过微小和小对象分配器管理内存,大于32KB的大对象直接分配。GC是并发的,使用写屏障和非压缩策略,分为扫描终止、标记、标记终止和扫除四个阶段。竞争检测用于查找数据竞争,debug包提供运行时调试功能,如堆栈跟踪。内部的atomic包提供原子操作保证线程安全,math包检测数学溢出。sys包包含系统特定常量,NotInHeap结构确保某些对象不被GC管理。
74 5
浅谈go垃圾回收与竞争检测
|
7月前
|
算法 Java 大数据
深入理解Go的垃圾回收机制
深入理解Go的垃圾回收机制
119 0
|
算法 Java Go
Go的垃圾回收器
go的垃圾回收器是怎么回收内存的?
64 0
|
7月前
|
存储 算法 Java
Go语言GC(垃圾回收)的工作原理
【2月更文挑战第23天】
163 0
|
7月前
|
算法 Java 程序员
没想到,Go语言垃圾回收是这样工作的!
没想到,Go语言垃圾回收是这样工作的!
80 0
没想到,Go语言垃圾回收是这样工作的!
|
7月前
|
监控 Java 编译器
优化Go语言程序中的内存使用与垃圾回收性能
【2月更文挑战第5天】本文旨在探讨如何优化Go语言程序中的内存使用和垃圾回收性能。我们将深入了解内存分配策略、垃圾回收机制,并提供一系列实用的优化技巧和建议,帮助开发者更有效地管理内存,减少垃圾回收的开销,从而提升Go程序的性能。
|
7月前
|
算法 Java Go
Go语言中的垃圾回收机制:原理、优化与影响
【2月更文挑战第5天】本文深入探讨了Go语言中的垃圾回收机制,包括其工作原理、性能优化方法以及对程序运行的影响。通过了解这些内容,读者可以更好地理解Go语言的内存管理特点,并在实际开发中更好地应对垃圾回收带来的挑战。
|
7月前
|
算法 Java Go
掌握Go的内存管理机制:垃圾回收与内存泄漏
掌握Go的内存管理机制:垃圾回收与内存泄漏
106 0