Go性能优化 | 青训营笔记

87 阅读2分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 4 天

Go性能优化

性能优化:提升处理能力,减少不必要消耗,充分挖掘算力。能够提高用户体验。优化主要包括两个层面:业务层以及程序运行时优化。

业务层优化

  1. 针对特定场景,具体问题具体分析

语言运行时优化

  1. 解决内存分配等问题
  2. tradeoffs

数据驱动

  1. 自动化性能分析工具--pprofs
  2. 依靠数据分析,优化最大瓶颈

自动内存管理

手动分配内存可能存在漏洞,需要GC来保证正确性和安全性。

GC任务: 分配新空间,找到存活对象,回收死亡空间

Mutator:业务线程,Collector:GC线程

CollectorGC必须感知对象指向关系的改变

GC算法评价:

安全性,吞吐率,暂停时间,内存开销

GC追踪垃圾回收(被回收的条件:指针指向关系不可达对象)

  1. 标记根对象,找到所有可达对象
  2. 清理:Copying GC,Mark-sweep GC(死亡对象标记为可分配),Mark-compact GC(移动并整理对象)

分代GC: 每个对象经历过GC的次数,不同年龄的对象制定不同的策略。

年轻代采用复制的方式做清理。老年代采用死亡对象可分配方法。

引用计数用来判断对象是否存活。缺点开销较大,无法回收环形数据结构。回收时可能会引入暂停。

Go内存分配

目标:为对象在heap上分配内存 提前将内存分块,先是申请一大块内存,然后分配不同大小的小内存。

还采用了缓存的机制进行内存分配

对象的分配是非常高频的操作,小对象占比高,

优化: Balanced GC 优先在G上进行分配。

问题是会导致内存被延迟释放。因此采取移动的方式管理小对象。其实就是分代管理的年轻代管理。

编译器和静态分析

编译器用于识别符合语法和非法的程序,分为分析部分(前端)和综合部分(后端)

静态分析:不执行程序代码,来推导程序行为。

Go编译器优化

为什么要编译器优化:用户无感知,编译后即可获得性能收益

现状:采用优化少

优化思路:场景:长期后端执行任务,用编译时间换更好的效果。

  1. 函数内联:将调用的函数体的副本替换到调用位置上。

    缺点:函数体变大,对cache不友好,生成的Go镜像变大

  2. 逃逸分析