Golang编译器优化 | 青训营笔记

371 阅读3分钟

这是我参与「第三届青训营 -后端场」笔记创作活动的的第15篇笔记

😆在这里,我对今天所新学到的Golang编译器优化做了一次总结

😜Golang的其他知识在哪里找呢,那你就问对了

👨‍💻Golang基础复习 - 掘金 (juejin.cn) 在这里我总结了一些这篇文章没有提到的一些知识

😊如果有小伙伴能想到更多知识,欢迎大家在评论区留言,那么我们就开始吧

👩‍💻👨‍💻哟西,一个棕~

😎😎😎我是小小分割线

编译器是什么

编译器是一个重要的系统软件,用来识别符合语法和非法的程序并生成正确且高效的代码

编译器的结构

image.png

在编译器的前端部分会进行

  1. 词法分析,生成词素

  2. 语法分析,生成语法树AST

  3. 语义分析,在语法树上做一些检查

    收集类型信息放入AST上,生成(decorated)AST

  4. 中间代码生成,生成intermediate representation(IR)

在编译器的后端部分会进行

  1. 代码的优化,机器无关优化,生成优化后的IR

  2. 代码生成,生成目标代码

静态分析

定义:不执行代码,而是去推断程序的行为,分析程序的性质

最常见的分析为两种:控制流的分析和数据流的分析

控制流(Control flow):分析程序执行的流程

数据流(Data flow):分析数据在控制流上的传递

过程内分析和过程间分析

过程内分析:仅在函数内部进行分析

过程间分析:考虑函数调用时的参数传递和返回值的数据流和控制流

过程间分析比较复杂,尽量避免过程间分析

Go编译器优化

Go编译器优化的优点:

  1. 用户无感知,重新编译就可以获得性能收益

  2. 是一个通用性优化

场景

面向后端,长期的执行任务

思路:使用编译时间换取更高效的机器码

字节跳动的产品 (Beast mode)

我们来看看这个产品用了什么优化手段

函数内联

将被调用的函数的函数体的副本直接替换到调用位置,同时重写代码来反映参数的绑定

优点:

  1. 消除函数调用开销,保存寄存器

  2. 将过程间分析转化为过程内分析

  3. 由于变成了过程内分析,能够拿到更多的性质,帮助其他优化,例如逃逸分析

缺点:

  1. 函数体变大,对cpu的指令缓存不友好

  2. 编译生成的Go变大

在大多数情况下都是正向优化,需要根据一定的策略去具体的决定是否做内联

逃逸分析

就是分析代码中指针的作用域

思路:

  1. 从对象分配的地方出发,沿着控制流观察对象的数据流

  2. 如果发现指针p在当前作用域s有以下任一操作

    作为参数传递给其他函数

    传递给全局变量

    传递给其他的goroutine

    传递给已逃逸的指针指向的对象

  3. 那么就说指针p指向的对象逃逸出s,反之没有

也就是说:p在s以外的地方能不能被访问到

函数内联能拓展函数边界,使得有些对象不逃逸了

而对于这个不会逃逸的对象我们可以选择在栈上分配

对象在栈上分配和回收是很快的

还可以减少在heap上的分配,降低GC的负担


以上就是我对今天所学到的Golang编译器优化的总结

😎😎😎又是我,我还是小小分割线

都用心看到这里了,那就求个赞吧😘

🥳🥳🥳如果小伙伴有其他的小知识,一定不要忘了在评论区讨论哟,多多讨论,生态才会越来越好