传说
- Go语言早期的gc非常烂,批评这个语言的火力90%都给了gc:“实习生写出来的。”
- 后期经过不断优化,go的gc已经非常优秀了,实时性极佳。
文章
- 于是我左看右看,找到了一篇细致的文章:https://zhuanlan.zhihu.com/p/334999060
总结
- 首先,Golang gc不是
引用计数
,采用是mark+sweep
的方式,这种方法天然就会把gc压力集中起来,导致性能瓶颈。 - 不断的性能改进:
- Go 1.3之前:主要靠STW(stop the world),停下来之后开始扫描,然后把扫不到的清理掉。蠢是蠢了掉,毕竟这个时候也还没开始自举。
- Go 1.3:小优化,mark完了就马上放开STW,后面再清理。
- Go 1.5:
三色标记扫描+写屏障
。三色扫描
的设计可以把扫描任务分解,利于并行处理,这当然能加一点速;为了干掉STW,搞出来了一个写屏障(增加引用和删除引用两种情况)
,应用在堆对象上,栈对象为了保证速度不能用这种写屏障,最后还是有一段STW。两种优化上去之后,速度基本能work了。 - Go 1.8:
三色标记扫描+混合写屏障
,此时的优化主要在写屏障上,栈对象还是不应用写屏障,但通过一些处理可以规避后续耗时的STW(gc开始时就扫描所有栈对象引用,全部标黑);堆对象用了更高效的混合写屏障,速度也提升了。这个版本的gc已经能称得上优秀。
- 总的思路就是把集中的大规模gc变成并行的、尽量不STW的持续过程,gc的吞吐量减少了,给应用的压力也就小了。
- 本质上还是区别于java的gc方式,应用场景聚焦于
高并发、高io、而并非计算密集的场景
。