Golang内存管理:GC算法剖析 前言 作为一门高性能的编程语言,Golang内存管理一直是开发者们关注的重点。作为Golang工程师,不了解内存管理会使得我们的代码出现内存泄漏等问题。因此,本文旨在深入探讨Golang的GC算法。 1. Golang GC 算法分类 Golang目前使用的是三色标记和清除算法(3-color Mark and Sweep),和Java的标记清除算法类似,一般分为以下几个步骤: 1) 根搜索(Root scanning):从固定的根开始扫描调用关系,标记被引用的对象。 2) 标记(Marking):从根对象开始,遍历整个堆,将被引用的对象标记为黑色。 3) 清除(Sweeping):将所有未被标记的对象清除,并将空间恢复给空闲链表。 2. 标记算法原理 2.1 标记时机 Golang运行时会分配一部分内存作为heap(堆),当堆中的对象达到一定的比例后,就会触发GC,进行垃圾回收。 2.2 标记流程 * GC开始前,所有对象都是白色的,标记位为0。 * 然后从根出发,遍历所有对象,将其标记为灰色,标记位为1,放入灰色对象队列 * 遍历灰色对象队列,取出一个对象,将其标记为黑色,所有引用它的对象也被标记后,放入黑色对象队列。 * 如果队列为空,则标记结束,所有没被标记的对象都是垃圾,可以被回收了。 2.3 并发标记 在并发标记中,会出现三色标记问题,即黑色对象引用灰色和白色对象,在标记结束前,灰色和白色对象之间还有引用关系,这时不能将所有白色对象都回收掉。因此Golang引入了三色标记和清除算法。 3. 三色标记和清除算法 3.1 状态 Golang中的对象有三种状态:黑色、灰色、白色。 * 黑色:已标记为存活的对象。 * 灰色:已发现但未标记为存活的对象。 * 白色:未发现的对象。 3.2 标记 在标记过程中,首先将根对象标记为灰色,并将灰色对象入队。然后遍历灰色队列,将灰色对象标记为黑色,将灰色对象的引用的白色对象标记为灰色,入队。不断遍历灰色队列,直到队列为空。 3.3 清除 清除阶段中,将所有白色对象回收,并将黑色和灰色对象标记为白色。 4. 安全点和边界栈 为了避免在标记时,出现指向新生代对象的指针,Golang使用了安全点和边界栈。 安全点是Golang程序执行期间,在程序整个执行过程中的某一时刻,GC程序可以安全地执行垃圾回收操作的时刻。Golang GC会在每个安全点进行检查,如果发现条件满足,则启动GC,并在安全点结束时恢复GC。 边界栈用于记录函数的退出地址,避免遍历调用栈时出现指向新生代的指针。 5. 总结 Golang内存管理采用了三色标记和清除算法,在并发标记时,使用了状态标记和安全点的方法来保证垃圾回收的准确性和高效性。同时,Golang GC 内部还有一组边界栈数据结构,来防止指针指向新生代对象,提升了GC的性能。