title: go_GC原理
category: Goroutine
date: 2021-07-25 22:23:06
tags:
- Golang
- GC
Mark & Sweep
Carbage Collection
现代高级编程语言管理内存的方式分为两种:自动和手动,像 C、C++ 等编程语言使用手动管理内存的方式,工程师编写代码过程中需要主动申请或者释放内存;而 PHP、Java 和 Go 等语言使用自动的内存管理系统,有内存分配器和垃圾收集器来代为分配和回收内存,其中垃圾收集器就是我们常说的 GC。主流的垃圾回收算法:
- 引用计数
- 追踪式垃圾回收
Go 现在用的三色标记法就属于追踪式垃圾回收算法的一种。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-A1g4CXQc-1628528668798)(go-GC原理/carbage-collection.png)]
Mark & Sweep
STW
stop the world
, GC 的一些阶段需要停止所有的 mutator
以确定当前的引用关系。这便是很多人对 GC 担心的来源,这也是 GC 算法优化的重点。
Root
根对象是 mutator
不需要通过其他对象就可以直接访问到的对象。比如全局对象,栈对象中的数据等。通过Root
对象,可以追踪到其他存活的对象。
Mark Sweep
两个阶段:**标记(Mark)**和 **清除(Sweep)**两个阶段,所以也叫 Mark-Sweep
垃圾回收算法。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LP7oc9vZ-1628528668800)(go-GC原理/GC-root.png)]
下面这个算法就是严格按照追踪式算法的思路来实现的:
Stop the World
Mark
:通过 Root 和 Root 直接间接访问到的对象, 来寻找所有可达的对象,并进行标记。Sweep
:对堆对象迭代,已标记的对象置位标记。所有未标记的对象加入freelist, 可用于再分配。Start the Wrold
这个算法最大的问题是 GC 执行期间需要把整个程序完全暂停,朴素的 Mark Sweep 是整体 STW
,并且分配速度慢,内存碎片率高。
标记过程需的要 STW
,因为对象引用关系如果在标记阶段做了修改,会影响标记结果的正确性。
并发 GC 分为两层含义:
- 每个
mark
或sweep ``本身是多个线程
(协程)执行的(concurrent
) mutator
和collector
同时运行(background
)
concurrent 这一层是比较好实现的, GC 时整体进行STW,那么对象引用关系不会再改变,对 mark 或者sweep 任务进行分块,就能多个线程(协程) conncurrent 执行任务 mark 或 sweep。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7vQo6iag-1628528668801)(go-GC原理/mark-STW.png)]