GO语言垃圾回收(GC)

Go语言的垃圾回收采用三色标记法,通过写屏障和辅助GC来自动管理内存,减少内存泄漏和手动管理的复杂性。在标记阶段,程序会StopTheWorld,然后从根对象开始标记,再通过写屏障确保标记的准确性。辅助GC会在用户代码分配对象速度过快时介入,帮助加速回收。调优GC可以通过减少对象分配、避免string与[]byte转化等方式提高效率。垃圾回收的触发条件包括内存大小阈值和定时时间阈值。
摘要由CSDN通过智能技术生成

 什么是垃圾回收

系统级别的编程语言中,需要coder堆内存小心的进行管理操作,控制内存的申请和释放。解决这个问题,过去通常采用两种方案

  • 内存泄漏检测工具

  • 智能指针

而后来的语言都采用了语言层面的自动内存管理,内存释放由虚拟局或运行的时候来自动进行管理。而这种对不再使用的内存资源进行自动回收的行为就称为垃圾回收。

go gc

当前golang使用的垃圾回收机制是三色标记法配合写屏障和辅助GC,三色标记法是标记-清除法的一种增强版本。

标记-清除法(mark and sweep)

共分为两步

  1. 标记。先Stop The World(STW),暂停整个程序的全部运行线程,将被引用的对象打上标记

  2. 清除没有被打标机的对象,即回收内存资源,然后恢复运行线程。

这样做有个很大的问题就是要通过STW保证GC期间标记对象的状态不能变化,整个程序都要暂停掉,在外部看来程序就会卡顿。

三色标记法

  1. 初始状态全部都是白色

  2. 从root根出发扫描所有根对象,将其标为灰色

  3. 分析灰色是否引用了其他对象,如果没有则标记为黑色;如果有,将其引用标记为灰色,其自身标记为黑色。

  4. 重复步骤3,直至灰色对象队列为空。

  5. 将白色部分的对象视为垃圾,进行回收

如何工作

Golang GC的大部分处理是和用户代码并行的

GC完整的工作流程

  1. Mark:

    1. Mark Prepare:初始化GC任务,包括开启写屏障(write barrier)和辅助GC(mutator assist),统计root对象的任务数量等。这个过程需要STW

    2. GC Drains:扫描所有root对象,包括全局指针和goroutine(G)栈上的指针(扫描对应G栈时需停止该G),将其加入标记队列(灰色队列),并循环处理灰色队列的对象,直到灰色队列为空。该过程后台并行执行

  2. Mark Termination: 完成标记工作,重新扫描(re-scan)全局指针和栈。因为Mark和用户程序是并行的,所以在Mark过程中可能会有新的对象分配和指针赋值,这个时候就需要通过写屏障(write barrier)记录下来,re-scan 再检查一下。这个过程也是会STW的。

  3. Sweep: 按照标记结果回收所有的白色对象,该过程后台并行执行

  4. Sweep Termination: 对未清扫的span进行清扫, 只有上一轮的GC的清扫工作完成才可以开始新一轮的GC。

写屏障

写屏障:该屏障之前的写操作和之后的写操作相比,先被系统其它组件感知。就是在每一轮GC开始时会初始化一个叫做“屏障”的东西,然后由它记录第一次scan时各个对象的状态,以便和第二次re-scan进行比对,引用状态变化的对象被标记为灰色以防止丢失,将屏障前后状态未变化对象继续处理。

辅助GC

从上面的GC工作的完整流程可以看出Golang GC实际上把单次暂停时间分散掉了,本来程序执⾏可能是“⽤户代码-->⼤段GC-->⽤户代码”,那么分散以后实际上变成了“⽤户代码-->⼩段 GC-->⽤户代码-->⼩段GC-->⽤户代码”这样。如果GC回收的速度跟不上用户代码分配对象的速度呢? Go 语⾔如果发现扫描后回收的速度跟不上分配的速度它依然会把⽤户逻辑暂停,⽤户逻辑暂停了以后也就意味着不会有新的对象出现,同时会把⽤户线程抢过来加⼊到垃圾回收⾥⾯加快垃圾回收的速度。这样⼀来原来的并发还是变成了STW,还是得把⽤户线程暂停掉,要不然扫描和回收没完没了了停不下来,因为新分配对象⽐回收快,所以这种东⻄叫做辅助回收。

调优gc

  1. 减少对象分配,合理重复利用

  2. 避免string与[]byte转化

    • 两者发生转换的时候,底层数据结结构会进行复制,因此导致 gc 效率会变低

  3. 少用+连接string

    • Go里面string是最基础的类型,是一个只读类型,针对他的每一个操作都会创建一个新的string。 如果是少量小文本拼接,用 “+” 就好;如果是大量小文本拼接,用 strings.Join;如果是大量大文本拼接,用 bytes.Buffer。

GC触发条件

  1. 超过内存大小阈值

  2. 达到定时时间 阈值是由一个gcpercent的变量控制的,当新分配的内存占已在使用中的内存的比例超过gcprecent时就会触发。比如一次回收完毕后,内存的使用量为5M,那么下次回收的时机则是内存分配达到10M的时候。也就是说,并不是内存分配越多,垃圾回收频率越高。 如果一直达不到内存大小的阈值呢?这个时候GC就会被定时时间触发,比如一直达不到10M,那就定时(默认2min触发一次)触发一次GC保证资源的回收。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值