Golang初识7 | 青训营笔记

70 阅读3分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 7 天

继续昨天的Go语言优化,今天的内容从语言编译器入手,重点是将没必要在运行时计算的中间结果提前计算出来。

编译器和静态分析

本部分的编译器优化是基于编译器的后端而非前端。

静态分析

静态分析是指编译器在执行代码前只通过推导程序的行为来确定程序的某些确定的中间性质,通俗理解就是在编译期就进行一些“预处理”,用更简单的中间“结果”来替换原先冗余的代码,同时保证程序的正确性。预处理的对象需要从“数据流”和“控制流”分别进行分析。从控制流来看,程序中的某些控制语句的分支是不可到达的因此可以直接将该分支删去。从数据流来看,某些运算实际上是提前已知的值之间的运算,可以提前在编译器分析阶段就将这些值计算出来。

过程内分析&过程间分析

过程内分析就是在函数的内部分别进行“数据流”和“控制流”的分析。而过程间分析则更加复杂,因为它需要进行函数的返回值与调用参数在整个程序中的“数据流”与“控制流”,因此分析的时候涉及到进入调用函数的内部和函数的返回值,这对于“静态”分析来说是比较困难的,因为只靠静态的扫描来分析程序中函数的返回值是困难的。

Go编译器优化

静态分析、过程内和过程间分析是编译时优化的重要内容,下面针对Go语言编译器提出具体的优化方案。

编译器优化的优点

编译器优化通过较长的编译时间换取程序在机器上执行的高效率,因此其优化具有通用性和用户完全无感知的特征,根据其特征可将其用于一些不是经常迭代的基础服务组件,提高用户体验。

函数内联

函数内联是编译优化常见的内容,C++中也有inline关键字,推荐编译器进行内联。当然函数内联显而易见的cons就是程序包的体积会变大,同时包含递归的函数是不能进行内联的,而且还要考虑内联函数的caller的函数体的大小。另一方面对常用的小功能函数进行内联,有利于我们将过程间静态分析,转为过程内静态分析,大大降低静态分析的难度。

逃逸分析

逃逸分析的优化主要是针对非逃逸对象,默认情况下所有新的对象都分配在heap上由自动内存管理系统管理回收,对于没有逃逸的对象我们可以把它分配到它所属于的Scope的栈上,这样减少了自动内存管理系统的工作,同时对象的回收和创建都被平摊在了栈的创建上,而栈的释放和分配是相当快速的。

Go语言部分的优化就到此为止。