这是我参与「第三届青训营 -后端场」笔记创作活动的的第2篇笔记。
主要内容
主要能学习到Go的编译器优化方案介绍:
- 编译器优化
背景
- 编译器优化的基本问题和思路
性能优化是为了什么呢
- 提升软件系统处理能力,减少消耗,充分发挥计算机的算力
- 用户体验
- 资源高效利用
编译器的结构
- 重要的系统软件
- 识别符合语法和非法的程序
- 生成正确且高效的代码
- 分析部分(前端)
- 词法分析,生成词素
- 语法分析,生成语法树
- 语义分析,收集类型信息,进行语义检查
- 中间代码生成,IR
- 综合部份
- 代码优化,机器无关优化,生成优化后的IR
- 代码生成,生成目标代码
相关概念
- 静态分析 :不执行程序代码,推导程序的行为,分析程序的性质
- 控制流:程序执行的流程
- 数据流: 数据在控制流上的传递
通过上述概念,我们来优化代码
过程内分析和过程间分析
- 过程内分析
- 仅在过程内部进行分析
- 过程间分析
- 考虑过程调用时参数传递和返回值的数据流和控制流
- 为什么过程分析会成为问题
- 过程间分析需要同时分析数据流和控制流,联合求解,较复杂
GO编译器的优化
- 目的:
- 现在的优化太少了
- 编译时间太少了,没有进行复杂的代码分析和优化
- 思路
- 面向后端长期执行任务
- 用编译时间换取搞笑的机器码
- 字节的方案
- Beast mode
函数内联
大多数情况下都是正向优化
- 内联 将函数的函数体做副本替换到调用位置上去
- 优点 消除调用开销,将过程内分析变为过程间分析,例如逃逸分析 使用micro-benchmark验证一下
- 缺点 函数体变大,编译生成的Go镜像变大
Beast Mode
- 调整函数内敛的策略,使更多的函数被内联,增加逃逸分析,使更多对象不逃逸,降低开销
- 代价:镜像文件增加10%,编译时间增加
- 优化:未逃逸的对象可以在栈上分配(分配和回收快,降低GC)
逃逸分析
分析代码中指针的动态作用域:指针在何处可以被访问
- 逃逸的几种情况:
- 作为参数传递给其他参数
- 传递给全局变量
- 传递给协程
- 传递给已经逃逸指针指向的对象