【Go语言内存管理详解】编译器和静态分析-Go编译器优化 | 青训营笔记

197 阅读4分钟

这是我参与「第五届青训营」伴学笔记创作活动的第 6 天,今天学习的内容是关于编译器和静态分析、Go编译器优化,根据课程内容整理学习笔记如下。

5.4 编译器和静态分析

5.4.1 编译器的结构

  • 重要的系统软件

  • 分析部分(前端 front end)

    • 词法分析,生成词素(lexeme)
    • 语法分析,生成语法树
    • 语义分析,收集类型信息,进行语义检查
    • 中间代码生成,生成 intermediate representation(IR)
  • 综合部分(后端 back end)

    • 代码优化,机器无关优化,生成优化后的IR
    • 代码生成,生成目标代码

    image.png

5.4.2 静态分析

  • 静态分析:不执行程序代码,推导程序的行为,分析程序的性质。

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

    image.png

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

    image.png

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

  • 通过分析控制流和数据流,我们可以知道更多关于程序的性质(properties) ,这些事实可以帮助我们做编译优化。

    • 例如上面的程序。我们通过分析数据流和控制流,知道这个程序始终返回 4。编译器可以根据这个结果做出优化。

    image.png

5.4.3 过程内分析与过程间分析

  • 过程内分析/函数内分析(Intra-procedural analysis):在函数内进行控制流和数据流的分析
  • 过程间分析/函数间分析(Inter-procedural analysis):除了函数内的分析,还需要考虑跨函数(函数调用时参数传递和返回值等) 的数据流和控制流(复杂,原因在如同名函数复用等问题,需要进行联合求解)

5.5 Go 编译器优化

5.5.1 概述

  • 目的

    • 用户无感知,重新编译即可获得性能收益
  • 通用的优化手段
  • 现状

    • 采用的优化较少
  • 追求编译时间短,因此没有进行复杂的代码分析和优化
  • 思路

    • 面向后端长期执行的任务
  • Tradeoff: 用适当增加编译时间换取更高性能的机器码

  • Beast mode

    • 函数内联
    • 逃逸分析
    • 默认栈大小调整
    • 边界检查消除
    • 循环展开
    • ......

5.5.2 函数内联 Inlining

  • 定义: 将被调用函数的函数体(callee)的副本替换到调用位置(caller)上,同时重写代码以反映参数的绑定

  • 优点

    • 消除函数调用开销,例如传递参数、保存寄存器等
    • 将过程间分析的问题转换为过程内分析,帮助其他分析(如逃逸分析)
  • 缺点

    • 函数体变大,instruction cache(icache)不友好
    • 编译生成的 Go 镜像文件变大
  • 函数内联在大多数情况下是正向优化,即多内联,会提升性能

  • 采取一定的策略决定是否内联

    • 调用和被调用函数的规模

5.5.3 Beast Mode

  • Go 内联的限制较多

    • 语言特性:interface, defer 等等,限制了内联优化
    • 内联策略非常保守
  • 字节跳动的优化方案Beast mode:修改了内联策略,让更多函数被内联

    • 降低了函数调用的开销
    • 增加了其他优化的机会:逃逸分析
  • 开销

    • Go 镜像大小略有增加(~10%)
    • 编译时间增加
    • 运行时栈扩展开销增加

5.5.4 逃逸分析

  • 定义:分析代码中指针的动态作用域,即指针在何处可以被访问

  • 大致思路

    • 从对象分配处出发,沿着控制流,观察数据流

    • 若发现指针 p 在当前作用域 s:

      • 作为参数传递给其他函数;
      • 传递给全局变量;
      • 传递给其他的 goroutine;
      • 传递给已逃逸的指针指向的对象;
    • 则指针 p 逃逸出 s,反之则没有逃逸出 s.

  • Beast mode:函数内联拓展了函数边界,更多对象不逃逸

  • 优化: 未逃逸出当前函数的指针指向的对象可以在栈上分配

    • 对象在栈上分配和回收很快:移动 sp 即可完成内存的分配和回收
    • 减少在堆上分配对象,降低 GC 负担