Go 语言的垃圾回收机制(Garbage Collection,GC)是其内存管理的重要组成部分,以下是相关介绍:
1、基本原理
- 标记 - 清除算法:Go 语言的垃圾回收主要基于三色标记 - 并发清除算法。首先,从根对象(如全局变量、当前执行函数的局部变量等)开始,递归地标记所有可达的对象。然后,遍历整个堆,清除未被标记的对象,即那些不可达的对象,回收它们占用的内存空间。
- 三色标记法:为了实现标记过程,Go 使用了三色标记法。将对象分为白色、灰色和黑色。初始时,所有对象都是白色。从根对象开始,将其标记为灰色,放入待处理队列。处理队列中的灰色对象,将其引用的对象标记为灰色,并将自身标记为黑色。重复这个过程,直到队列为空。最后,剩下的白色对象就是不可达的垃圾对象。
2、三色标记法的三种颜色:
- 白色:表示尚未被垃圾回收器访问过的对象,在垃圾回收过程开始时,初始时,所有对象默认都是白色。从根对象出发无法到达的白色对象,最终会被认定为垃圾对象,可以被回收。
- 灰色:代表已被垃圾回收器访问过,但它引用的其他对象尚未全部被访问完的对象。在标记过程中,灰色对象是正在处理的对象,其引用的白色对象会被标记为灰色,并放入待处理的灰色集合中。
- 黑色:表示已被垃圾回收器访问过,并且其引用的所有对象也都已被访问过的对象。黑色对象在本次垃圾回收中被认为是存活的对象,不会被回收。
3、标记过程
- 初始化:从根对象(如全局变量、栈上的变量等)开始遍历,将根对象标记为灰色,并放入一个待处理的灰色集合中。
- 标记阶段:从灰色集合中取出一个灰色对象,将其所有直接引用的对象标记为灰色(如果这些对象原本是白色的话),并放入灰色集合中,并将当前对象标记为黑色。不断重复这个过程,直到灰色集合为空。此时,所有可达的对象都被标记为了黑色,而不可达的对象仍然是白色。
- 并发执行:Go 语言的垃圾回收器在标记阶段与应用程序的执行并发进行,通过将标记工作分解为多个小步骤,与应用程序的执行交替进行,减少标记阶段对应用程序的停顿时间。
根对象?
根对象是指那些可以直接被程序访问到的对象,包括:
全局变量、逃逸的函数局部变量、CPU 寄存器中存储的变
全局变量在程序运行期间通常不会被回收,因为它们在整个程序的生命周期内都处于可达状态。
4、清除阶段:
遍历堆中的所有对象,将那些仍然是白色的对象回收,释放它们占用的内存空间。
5、优化策略
- 分代回收:Go 语言将内存对象分为不同的代,新创建的对象通常在年轻代,经过多次垃圾回收后仍然存活的对象会被晋升到老年代。年轻代的垃圾回收频率较高,因为大多数对象在创建后很快就不再被使用,老年代的回收频率较低。
- 并发回收:Go 的垃圾回收可以与用户代码并发执行,减少垃圾回收对程序执行的暂停时间。在垃圾回收过程中,大部分工作可以在后台进行,只有在一些关键阶段,如标记开始和结束时,才需要暂停用户程序,以确保标记的准确性。
- 写屏障:为了保证在并发垃圾回收过程中对象引用关系的正确性,Go 语言使用了写屏障技术。写屏障在对象的指针被修改时触发,当应用程序修改指针时,写屏障会记录这些修改,以确保 GC 不会遗漏任何可达对象。具体来说,写屏障会将新写入的对象标记为灰色,确保它们在标记过程中被正确访问到。
6、触发条件
- 定时触发:Go 语言运行时会定期检查是否需要进行垃圾回收,这个时间间隔是动态调整的,根据程序的运行情况和内存使用情况来确定。
- 内存分配触发:当内存分配达到一定阈值时,也会触发垃圾回收。例如,当新分配的内存超过了当前堆内存的一定比例时,就会启动垃圾回收,以释放一些内存空间。