go 垃圾回收
本文基于整个go的gc发展,来研究其gc的演变过程,不单打针对某个版本的gc,因为go的gc一直在演变
一.GO GC的发展历史
- go v1.1 : 标记清除法,整个过程都需要STW
- go v1.3 : 标记清除法,标记过程仍然需要STW,但是清除过程并行化,gc pause约为几百ms
- go v1.5 : 引入插入写屏障技术的三色标记法,仅在堆空间启动插入写屏障,全部扫描后需要STW重新扫描栈空间,gc pause耗时降到10ms以下
- go v1.8 : 引入混合写屏障技术的三色标记法,仅在堆空间启动混合写屏障,不需要在GC 结束后对栈空间重新扫描,gc pause时间降至0.5ms以下
- go 1.1.4 引入新的页分配器用于优化内存分配的速度
二. 常用GC算法
总共分为三类:
- 引用计数法
- 追踪式法
- 可达性分析法
- 标记-复制法
- 标记-清除法
- 标记-整理法
- 三色标记法
- 分代收集法
1.引用计数
引用计数会为每个对象维护一个计数器,当该对象被其他对象引用时加1,引用失效时减1,当引用次数为0后即可回收对象
优点:
- 原理和实现都比较简单
- 回收及时性高,引用计数为0则立即回收,不需要想其他GC机制需要等待特定的时间回收
- 不需要暂停应用即可完成回收
缺点:
- 无法解决循环引用的问题
- 时间和空间成本高:每个对象需要额外的空间来存储引用计数,在栈上修改引用计数的时间成本高(因为需要额外的原子操作来保证线程安全)
- 无法保证耗时:引用计数是一种摊销算法,会将内存的回收分摊到整个程序的运行过程,当销毁一个很大的树形结构时无法保证响应时间
2.可达性分析算法
该算法属于追踪式算法,目的是回收不可达对象,可达对象主要包括两类:
- GC root对象: 包括全局对象,栈上对象
- 与GC root对象通过引用链相连的对象
对于不可达对象,我们认为该对象为垃圾对象,应该被回收
同上述的引用计数法相比,追踪式算法具有如下优点:
- 解决了循环引用的问题
- 占用的空间少了
和引用计数法