Go内存分配及编译器优化 | 青训营笔记

43 阅读2分钟

Go内存分配

分块

目标: 为对象在heap上分配内存 提前将内存分块:调用系统调用mmap()向OS申请一大块内存,先将内存划分成大块,再将大块继续划分成特定大小的小块 对象分配:根据对象的大小,选择最合适的块返回

缓存

  • TCMalloc
  • mcache管理一组mspan
  • 当mcache中的mspan分配完毕,向mcentral申请带有未分配块的mspan

内存管理优化

  • 对象分配:每秒分配GB级别的内存
  • 小对象占比高
  • go内存分配比较耗时

Balanced GC

  • 指针碰撞风格的对象分配
  • 实现了copying GC
  • 性能收益

编译器和静态分析

编译器

  • 词法分析,生成词素
  • 语法分析,生成语法树
  • 语义分析,收集类型信息,进行语义检查
  • 中间代码生成

静态分析

不执行程序代码,推导程序行为,分析程序的性质

  • 控制流:程序执行的流程
  • 数据流:数据在控制流上的传递

过程内分析和过程间分析

  • 过程内分析:仅在函数内部进行分析
  • 过程间分析:考虑函数调用时参数传递和返回值的数据流和控制流

Go编译器优化

Beast Mode 提升代码性能

函数内联

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

优点:

  • 消除函数调用开销
  • 将过程间分析转化为过程内分析

缺点:

  • 函数体变大
  • 编译生成的go镜像变大

函数内联在大多数情况下是正向优化

逃逸分析

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

优化:未逃逸的对象可以在栈上分配

  • 对象在栈上分配和回收很快
  • 减少在heap上的分配,降低GC负担