这是我参与「第三届青训营 -后端场」笔记创作活动的的第15篇笔记
😆在这里,我对今天所新学到的Golang编译器优化做了一次总结
😜Golang的其他知识在哪里找呢,那你就问对了
👨💻Golang基础复习 - 掘金 (juejin.cn) 在这里我总结了一些这篇文章没有提到的一些知识
😊如果有小伙伴能想到更多知识,欢迎大家在评论区留言,那么我们就开始吧
👩💻👨💻哟西,一个棕~
😎😎😎我是小小分割线
编译器是什么
编译器是一个重要的系统软件,用来识别符合语法和非法的程序并生成正确且高效的代码
编译器的结构
在编译器的前端部分会进行
-
词法分析,生成词素
-
语法分析,生成语法树AST
-
语义分析,在语法树上做一些检查
收集类型信息放入AST上,生成(decorated)AST
-
中间代码生成,生成intermediate representation(IR)
在编译器的后端部分会进行
-
代码的优化,机器无关优化,生成优化后的IR
-
代码生成,生成目标代码
静态分析
定义:不执行代码,而是去推断程序的行为,分析程序的性质
最常见的分析为两种:控制流的分析和数据流的分析
控制流(Control flow):分析程序执行的流程
数据流(Data flow):分析数据在控制流上的传递
过程内分析和过程间分析
过程内分析:仅在函数内部进行分析
过程间分析:考虑函数调用时的参数传递和返回值的数据流和控制流
过程间分析比较复杂,尽量避免过程间分析
Go编译器优化
Go编译器优化的优点:
-
用户无感知,重新编译就可以获得性能收益
-
是一个通用性优化
场景
面向后端,长期的执行任务
思路:使用编译时间换取更高效的机器码
字节跳动的产品 (Beast mode)
我们来看看这个产品用了什么优化手段
函数内联
将被调用的函数的函数体的副本直接替换到调用位置,同时重写代码来反映参数的绑定
优点:
-
消除函数调用开销,保存寄存器
-
将过程间分析转化为过程内分析
-
由于变成了过程内分析,能够拿到更多的性质,帮助其他优化,例如逃逸分析
缺点:
-
函数体变大,对cpu的指令缓存不友好
-
编译生成的Go变大
在大多数情况下都是正向优化,需要根据一定的策略去具体的决定是否做内联
逃逸分析
就是分析代码中指针的作用域
思路:
-
从对象分配的地方出发,沿着控制流观察对象的数据流
-
如果发现指针p在当前作用域s有以下任一操作
作为参数传递给其他函数
传递给全局变量
传递给其他的goroutine
传递给已逃逸的指针指向的对象
-
那么就说指针p指向的对象逃逸出s,反之没有
也就是说:p在s以外的地方能不能被访问到
函数内联能拓展函数边界,使得有些对象不逃逸了
而对于这个不会逃逸的对象我们可以选择在栈上分配
对象在栈上分配和回收是很快的
还可以减少在heap上的分配,降低GC的负担
以上就是我对今天所学到的Golang编译器优化的总结
😎😎😎又是我,我还是小小分割线
都用心看到这里了,那就求个赞吧😘
🥳🥳🥳如果小伙伴有其他的小知识,一定不要忘了在评论区讨论哟,多多讨论,生态才会越来越好