Go是如何实现垃圾回收的?
Go的垃圾回收(GC)可以想象成一种自动的清洁工,它的工作是在你的Go程序运行时不断地清理不再需要的数据,从而防止内存被无用数据占满。这个过程大致可以比作打扫房间:首先要确定哪些东西是你还需要的(标记阶段),然后将不需要的东西扔掉(清除阶段)。让我们通俗地理解一下这个过程:
打扫前的准备(标记阶段)
想象一下,你的房间里有很多盒子(内存中的对象),有些盒子里装的是你需要的东西,有些则是不需要的。但在开始打扫之前,你并不知道哪些是需要的。所以,你开始检查每个盒子(标记活动对象):
- 你首先检查那些容易判断的,比如手边的东西(根对象),然后是手边东西指向的东西(从根对象可达的对象)。
- 当你检查一个盒子时,你用不同的标记笔记下这是一个“需要保留”的盒子。
- 这个过程中,你不停地移动,同时保持你的日常活动不受影响(并发执行)。
决定什么需要扔掉(标记结束)
虽然你在标记的过程中尽量不打扰到房间的正常使用,但最后你需要一个短暂的时间来确认一下是否所有需要的东西都被检查过了,确保没有遗漏(标记终止)。
开始打扫(清除阶段)
- 接下来,你开始清理那些没有标记的盒子,也就是你不再需要的东西(清除不活动的对象)。这个过程同样可以在你进行其它活动时一边进行(并发清除)。
- 你不需要一次性停下所有活动就开始清理,而是可以边做边清,减少影响。
一些小技巧(优化)
- 为了确保在清理过程中不会把新产生的需要的东西误判为垃圾,你使用了一种特别的记号(写屏障),这样即使在清理过程中也能正确处理新出现的东西。
- 你会根据房间使用情况和盒子的数量自动决定打扫的频率,如果房间很乱(内存分配快),就会增加打扫的次数,以保持房间的整洁(GC触发机制)。
通过这种方式,Go确保了程序中不再需要的内存可以被及时回收,从而让程序运行得更加高效,同时尽量减少了打扫工作对你的日常活动的影响。
知识点
让我们用一个简单的比喻来理解三色标记法和写屏障,把它想象成是组织一场大型派对的过程。
三色标记法
假设你要举办一场派对,邀请了很多朋友(对象)。为了确保派对顺利进行,你决定对来宾进行分类(标记):
- 黑色:确认来的朋友(已经检查过的对象),这些人已经到达派对现场,你确定他们不会离开。
- 灰色:已经收到邀请,但还没确定是否来的朋友(已检查但其关联的对象未全部检查的)。他们在路上,可能会带着更多的朋友一起来。
- 白色:还没发出邀请的朋友(未检查的对象)。你还没有确定是否需要他们来参加派对。
派对准备开始时,你先找到直接联系的朋友(根对象),将他们标记为灰色,表示他们是第一批受邀请的。然后,这些灰色的朋友可能会告诉你他们会带哪些朋友来,你也将这些朋友标记为灰色。一旦确认了某个朋友和他带的朋友都收到邀请,你就可以把他们标为黑色,表示这部分准备工作完成。整个过程中,那些最终没有被标记为黑色或灰色的朋友(白色),就是不会参加派对的,因此你不需要为他们准备食物和饮料(被清理的内存)。
写屏障
现在,想象在派对筹备过程中,你实施了一个规则:如果有朋友在最后一刻决定带额外的人来,他们需要先告诉你(写屏障)。这样即使在你整理名单的过程中,也能确保所有突然增加的人都被正确处理,没有人会被漏掉。这个规则帮助你动态调整计划,确保派对上的食物和饮料足够,同时不会浪费资源准备给最终没有来的人。
这个比喻中的“朋友”就是程序中的对象,“食物和饮料”代表程序分配的资源。三色标记法帮助垃圾收集器高效地识别出不再需要的对象,而写屏障确保在这个过程中对对象关系的任何更改都被正确处理,防止了垃圾收集过程中的数据不一致问题。
总结
Go的垃圾回收(GC)实现主要依赖于并发的、标记-清除算法,以及一些优化技术来减少GC引起的延迟。下面是Go垃圾回收的基本工作流程和特性:
基本工作流程
-
标记阶段(Mark Phase):垃圾收集器遍历所有的根对象(比如全局变量和当前所有goroutine的栈上的变量),然后递归地标记所有从这些根对象可达的对象为活动的。这个过程是并发进行的,意味着它和应用程序的代码同时运行,减少了程序的暂停时间。
-
标记终止(Mark Termination):为了完成标记过程,需要一个短暂的停顿,确保所有的活动对象都被标记。这个阶段尽可能短,以减少对程序运行的影响。
-
清除阶段(Sweep Phase):在这一阶段,垃圾收集器会遍历堆上的所有对象,释放那些在标记阶段未被标记为活动的对象占用的内存。清除阶段通常也是并发进行的,不需要程序暂停。
特性和优化
-
写屏障(Write Barrier):Go使用写屏障技术,在标记阶段并发执行时,保证新生成的对象和对象引用更新的正确性。当程序修改一个对象的指针时,写屏障会确保这些变化不会破坏垃圾收集器的标记过程。
-
并发GC:Go的垃圾回收设计为并发执行,意味着GC的大部分工作是与程序的其它部分同时运行的,极大地减少了GC引起的停顿时间。
-
三色标记:在标记阶段,Go垃圾收集器使用“三色”标记算法,其中对象可以被标记为白色(未检查的)、灰色(已检查但其指向的对象未全部检查的)或黑色(已检查且其指向的对象也全部检查过的)。这有助于有效地管理和跟踪对象的活跃状态。
-
GC触发机制:Go的GC是自适应的,它根据堆的大小和程序的分配速率动态调整触发时机。这意味着如果程序分配内存的速度很快,GC就会更频繁地运行,以避免使用过多的内存。
Go的垃圾回收机制经过精心设计,以尽可能减少对程序性能的影响,同时保证高效地回收未使用的内存。这使得Go非常适合构建需要长时间运行和高性能的服务和应用程序。
转载自:https://juejin.cn/post/7344955441304174632