1.编译器和静态分析
1.1编译器的结构

1.2静态分析
不执行代码,推导程序的行为,分析程序的性质。
1.3控制流
控制流:程序的执行流程
1.4数据流
数据流:数据在控制流上的传递

上图的程序转换成控制流图 (control-flow graph)

1.5Intra-procedural analysis、Inter-procedural analysis
通过分析控制流和数据流,我们可以知道更多关于程序的性质(properties) ,这些事实可以帮助我们做编译优化。
例如上面的程序。我们通过分析数据流和控制流,知道这个程序始终返回 4。编译器可以根据这个结果做出优化。

Intra-procedural analysis: 函数内分析:在函数内进行控制流和数据流的分析
Inter-procedural analysis: 函数间分析:除了函数内的分析,还需要考虑跨函数的数据流和控制流,例如参数传递,函数返回值等
2.Go 编译器优化
2.1目的
1.用户无感知,重新编译即可获得性能收益
2.通用的优化手段
2.2现状
1.采用的优化较少
2.追求编译时间短,因此没有进行复杂的代码分析和优化
2.3思路
1.面向后端长期执行的任务
2.用适当增加编译时间换取更高性能的代码
2.4函数内联
2.4.1定义
定义:将被调用函数的函数体的副本替换到调用位置上,同时重写代码以反映参数的绑定
2.4.2优点
优点:
1.消除调用开销
2.将过程间分析的问题转换为过程内分析,帮助其他分析
2.4.3缺点
缺点:
1.函数体变大
2.编译生成的 Go 镜像文件变大
2.4.4特点
函数内联在大多数情况下是正向优化,即多内联,会提升性能
2.4.5采取一定的策略决定是否内联
采取一定的策略决定是否内联:
1.调用和被调用函数的规模
2.4.6Go 内联的限制
Go 内联的限制:
1.语言特性:interface, defer 等等,限制了内联优化
2.内联策略非常保守
2.4.6字节跳动的优化方案
字节跳动的优化方案:
1.修改了内联策略,让更多函数被内联
2.增加了其他优化的机会:逃逸分析
2.4.7开销
开销:
1.Go 镜像大小略有增加
2.编译时间增加
3.运行时栈扩展开销增加
3.逃逸分析
3.1定义
定义:分析代码中指针的动态作用域,即指针在何处可以被访问
3.2大致思路
从对象分配处出发,沿着控制流,观察数据流。若发现指针 p 在当前作用域 s:
1.作为参数传递给其他函数;
2.传递给全局变量;
3.传递给其他的 goroutine;
4.传递给已逃逸的指针指向的对象;
则指针 p 逃逸出 s,反之则没有逃逸出 s.
3.3优化
优化:未逃逸出当前函数的指针指向的对象可以在栈上分配
1.对象在栈上分配和回收很快:移动 sp 即可完成内存的分配和回收;
2.减少在堆上分配对象,降低 GC 负担。