这是我参与「第三届青训营 -后端场」笔记创作活动的的第3篇笔记
Go语言优化
什么是性能优化?为什么要做性能优化?
一个观点:性能优化是充分挖掘计算机的算力,减少不必要的消耗。做性能优化既能提高用户体验,又能降低开销。
性能优化层面
业务代码 -> SDK -> 基础库 -> 语言运行时 -> OS。
业务层代码很好优化,因为有具体场景,还是普通开发写的。
语言运行时优化要考虑的方面相对多,要综合所有使用者做权衡。
注意,优化一定要基于数据。要看大性能瓶颈,抓住主要矛盾。同时,优化也要保证软件质量,尽量不影响其他接口,一定要保证稳定性。
自动内存管理
自动内存管理一方面可以降低心智负担,另一方面可以保证内存使用的正确性。
比较常见的问题是 double free 和 use after free。
相关概念
Mutator 用户线程,申请空间,修改引用关系。
Collector GC:垃圾回收线程
注意,前两者会暂停。最后的不会。最后的是Concurrently GC。
Concurrently GC它的挑战很大。因为你要感知Mutator对引用关系的改变。
可达性分析算法
第一步,标记root对象。这里涉及到GC ROOTS。比如静态变量、全局变量、常量、栈上对象。这些对象之所以可以当作root是因为之后可能还要用。
第二步,标记可达对象。就是递归标记。
第三步,清理不可达对象。标记清除、复制、收缩。
引用计数算法
这是我见过的最好的引用计数算法的ppt。
比如weak reference,可以解决引用计数的弊端,比如swift。
Go内存管理与优化
Go的内存分配做法:提前申请一大块内存然后分成小块。
分块
类似OS里的SLAB。注意这里的包含指针的对象块(scan mspan),这里提到ta主要是指GC的时候需要顺着他tracing。
缓存
意思就是先找大块,大块里找个小块。找不到去找下个大块。如果一个缓存里的所有大块都用没了,向central要一个大块。和银杏树的SLAB差不多。
优化——Balanced GC
这看起来不是很酷··因为我理解这就是TLAB,我以为是更牛逼的东西。Go的对象没有对象头,需要额外数据结构去记录一个GAB里有哪些对象,对象的起始地址之类的(用位图)。
但事实上,把东西讲得简单本身就是高手才能做到的。不应该眼高手低,也不应该因为有人做过就否定字节的Balanced GC。 其实他很酷。
这里确实很酷,应用标记复制思想去清理内存。这个阶段发生在最后的垃圾清理阶段。
解释一下这里的必要性。假设我们有两个GAB,占用内存2KB。里面的存活对象可能只有1B。在这种时候,我们也无法让GC回收这两KB的空间。我们需要把这1B存活对象拷贝到新的GAB中,才能回收这两KB。这两KB里有1999B都是垃圾。
编译器和静态分析
静态分析
在控制流上传播数据流的信息,可以做程序优化。
过程内分析和过程间分析:一个是只在函数内,一个是考虑函数的入参、出参。
Go编译器优化
虽然很有意思但是··这好像在开倒车。go就是不想让编译慢,你故意弄慢多做点优化。。
函数内联
同样地,这也是我第一次见到函数内联的缺点。