美文网首页Golang随笔-生活工作点滴
Go 内存管理 -- 垃圾回收

Go 内存管理 -- 垃圾回收

作者: 邹志全 | 来源:发表于2019-07-15 22:18 被阅读13次

前言

go作为一个非常年轻的语言,吸取了各个语言的优点,比如说Java中优秀的垃圾回收,来释放程序员一部分精力。
本篇要说的就是垃圾回收,常见的垃圾回收算法有标记-清除、标记整理、复制,然后在这些算法基础上有分为分代&非分代回收,这些算法都非常优秀,只是面对的场景不同罢了,但是要是想透彻的理解垃圾回收,看Java中的实现再合适不过了,如果能对于Java中的垃圾回收非常熟悉,理解go的垃圾回收将非常简单。
go中的垃圾回收官方是这么描述的:非分代的、非紧缩的、写屏障的并发标记清除的垃圾回收。

标记清除

标记清除指的是对于那些已经不会再使用的对象进行标记,标记完成后,对于标记的对象进行清除。


image.png

很显然如果使用标记清除算法:
1、确定标记的起点GCRoot
2、存在一定的内存碎片
3、效率相对于复制、整理 效率要稍微高一些
但标记清除是最常见的垃圾回收算法,Java 中CMS等垃圾回收器用的就是这个。
在标记的过程中有一个所有垃圾回收算法(涉及GCRoot的初始标记)都有的问题stop-the-world
标记&清理的过程可以是串行的(效率很低),也可以是并发的。

三色标记

三色标记是一种在传统的标记清除算法基础上衍生出来的一个改进的并发标记算法:
1、首先创建三个集合:白、灰、黑
2、将所有对象放入白色集合中
3、然后从根节点开始遍历所有对象(注意这里并不递归遍历),把遍历到的对象从白色集合放入灰色集合。
4、之后遍历灰色集合,将灰色对象引用的对象从白色集合放入灰色集合,之后将此灰色对象放入黑色集合
5、重复 4 直到灰色中无任何对象
6、通过write-barrier检测对象有变化,重复以上操作
7、收集所有白色对象(垃圾)


image.png

非常关键的一点是GCRoot的确定,这是整个算法的开端:
当前goroutine的栈和全局数据区中的对象作为GCRoot。

三色标记中的并发标记

所谓的并发标记就是指在goroutine执行的过程中能进行标记行为,这里采用的方式与Java的CMS方式比较像,通过写屏障来保证正确性。
比如说:当从A这个GC root找到引用对象B时,B变灰A变黑。这时用户goroutine执行把A到B的引用改成了A到C的引用,同时B不再引用C。然后GC goroutine又执行,发现B没有引用对象,B变黑。而这时由于A已经变黑完成了扫描,C将当做白色不可达对象被清除,这里就会出现一个不该被清理的对象被清理了。
而写屏障就是在这个出错的地方做了下判断:
当发现A已经标记为黑色了,若A又引用C,那么把C变灰入队。go gc时借助一个队列,也就是gc-work来完成非递归遍历。

强制回收

因为系统启动或者短时间内大量分配对象这些原因,会将垃圾回收的gc_trigger(垃圾回收的触发器)的标准瞬间推高。当服务正常后,活跃对象远小于这个阈值,造成垃圾回收无法触发。
所以需要有一个强制回收的触发,sysmon每隔2分钟强制触发GC一次。强制GC的goroutine一直park在后台,直到sysmon将它唤醒开始执行gc。

GC整体过程

Goff to Gmark
每次的gcstart都是满足gc_triger时由mallocgc触发,整个的启动过程是stop the world的,这个过程启动了所有的GC工作协程,进入GCMark状态使能写屏障,启动gcController。简单来说就是确定GCroot相关的goroutine。
Gmark
这个阶段是标记阶段,拿到准备好的goroutine来做标记,但是一开始就gopark当前的goroutine(上个阶段),直到被gccontroller的findRunnableGCWorker唤醒。
唤醒后进入标记阶段,每个worker都去gc-work中拿节点(节点置黑),然后处理当前节点看有没有指针和没标记的对象,继续入队子节点(灰化节点),直到队列为空。
Gmarktermination
标记结束后调用gcMarkDone
Gsweep
具体的清除行为,有多个时机可以出发Gsweep,如果是并发清除的话,需要先回收未被标记的heap区,然后唤醒进行sweep的 goroutine。
关于整体回收这一块儿内容,大家有兴趣可以看一下源码。
关于go的垃圾回收暂时就先介绍这么多。
关于go的内存管理后续会单独出一个系列,所以本系列仅仅阐述了一个内存管理的梗概和基础概念。

相关文章

  • Go 内存管理 -- 垃圾回收

    前言 go作为一个非常年轻的语言,吸取了各个语言的优点,比如说Java中优秀的垃圾回收,来释放程序员一部分精力。本...

  • go-内存机制(3)

    go的内存分配 Golang有一套自己的内存管理机制,自主的去完成内存分配、垃圾回收、内存管理等过程,从而避免频繁...

  • Java GC

    概述 GC => 垃圾回收 = 回收可用空间 + 压缩内存 内存管理 手动内存管理 => C | C++ 自动内存...

  • android--垃圾回收与内存优化

    什么是垃圾回收 对比C/C++这种需要自己管理内存的语言 java可以实现自动内存管理和回收 垃圾回收器负责回收程...

  • 常见GC算法与V8引擎

    内存管理 垃圾回收与常见GC算法 V8引擎的垃圾回收 Performance工具 代码优化实例 内存管理 为什么要...

  • Go内存分配机制总结

    GO语言内存管理子系统主要由两部分组成:内存分配器和垃圾回收器(gc)。内存分配器主要解决小对象的分配管理和多线程...

  • Android性能调优(4) — 内存泄漏与内存抖动

    在上一遍《Android性能调优(3)—内存管理与垃圾回收》我们对Android内存管理与垃圾回收有了一定的认识。...

  • 内存管理

    内存管理1、什么时候触发垃圾回收? 垃圾回收器周期性运行,如果分配的内存非常多,那么回收工作也会很艰巨,确定垃圾回...

  • JavaScript的垃圾回收机制

    大纲 1、认识垃圾回收机制2、垃圾回收机制的原理3、垃圾回收机制的标记策略4、垃圾回收机制与内存管理 1、认识垃圾...

  • Go 语言内存管理(四):垃圾回收

    介绍 编写 Go 代码不需要像写 C/C++ 那样手动的 malloc和 free内存,因为 malloc 操作由...

网友评论

    本文标题:Go 内存管理 -- 垃圾回收

    本文链接:https://www.haomeiwen.com/subject/ngjhkctx.html