Golang内存管理--垃圾回收原理
所谓垃圾就是不再需要的内存块,这些垃圾如果不清理就没办法再次被分配使用,在不支持垃圾回收的编程语言里,
这些垃圾内存就是泄露的内存。
垃圾回收算法
引用计数:对每个对象维护一个引用计数,当引用该对象的对象被销毁时,引用计数减1,当引用计数器为0是
垃圾回收的核心就是标记出哪些内存还在使用中(即被引用到),哪些内存不再使用了(即未被引用),把 未被引用的内存回收掉,以供后续内存分配时使用。
内存块1、2、4号位上的内存块已被分配(数字1代表已被分配,0 未分配)。变量a, b为一指针,指向内存 的1、2号位。内存块的4号位曾经被使用过,但现在没有任何对象引用了,就需要被回收掉。 垃圾回收开始时从root对象开始扫描,把root对象引用的内存标记为”被引用”,考虑到内存块中存放的可能是指针,所以还需要递归的进行标记,全部标记完成后,只保留被标记的内存,未被标记的全部标识为未分配即完成了回收。
内存标记
span中维护了一个个内存块,并由一个位图allocBits表示每个内存块的分配情况。在span数据结构中还有另一个位图gcmarkBits用于标记内存块被引用情况。
allocBits记录了每块内存分配情况,而gcmarkBits记录了每块内存标记情况。标记阶段对每块内存 进行标记,有对象引用的的内存标记为1(如图中灰色所示),没有引用到的保持默认为0. allocBits和gcmarkBits数据结构是完全一样的,标记结束就是内存回收,回收时将allocBits指向 gcmarkBits,则代表标记过的才是存活的,gcmarkBits则会在下次标记时重新分配内存。
三色标记法
这里的三色,指的是对应了垃圾回收过程中的三种对象的状态:
灰色:对象在标记队列中等待
黑色:对象已被标记,gcmarkBits对应的 1(该对象不会在本次GC中被清理)
白色:对象未被标记,gcmarkBits对应的 0 (该对象会在本次GC中被清理)
当前内存中有A~F一共6个对象,根对象a,b本身为栈上分配的局部变量,根对象a、b分别引用了对象A、B, 而 B对象又引用了对象D,则GC开始前各对象的状态如下图所示:
初始状态下都是白色的。
紧接着开始扫描根对象a,b
由于根对象引用了对象A、B,那么A、B变为灰色对象,接下来就开始分析灰色对象,分析A时,A没有引用其他对象很快就转入黑色,B引用了D,则B转入黑色的同时还需要将D转为灰色,进行接下来的分析。
上图中灰色对象只有D,由于D没有引用其他对象,所以D转入黑色。标记过程结束:
最终,黑色的对象会被保留下来,白色的会被回收。