这是我参与「第五届青训营 」伴学笔记创作活动的第 4 天
Go性能优化
性能优化:提升处理能力,减少不必要消耗,充分挖掘算力。能够提高用户体验。优化主要包括两个层面:业务层以及程序运行时优化。
业务层优化
- 针对特定场景,具体问题具体分析
语言运行时优化
- 解决内存分配等问题
- tradeoffs
数据驱动
- 自动化性能分析工具--pprofs
- 依靠数据分析,优化最大瓶颈
自动内存管理
手动分配内存可能存在漏洞,需要GC来保证正确性和安全性。
GC任务: 分配新空间,找到存活对象,回收死亡空间
Mutator:业务线程,Collector:GC线程
CollectorGC必须感知对象指向关系的改变
GC算法评价:
安全性,吞吐率,暂停时间,内存开销
GC追踪垃圾回收(被回收的条件:指针指向关系不可达对象)
- 标记根对象,找到所有可达对象
- 清理:Copying GC,Mark-sweep GC(死亡对象标记为可分配),Mark-compact GC(移动并整理对象)
分代GC: 每个对象经历过GC的次数,不同年龄的对象制定不同的策略。
年轻代采用复制的方式做清理。老年代采用死亡对象可分配方法。
引用计数用来判断对象是否存活。缺点开销较大,无法回收环形数据结构。回收时可能会引入暂停。
Go内存分配
目标:为对象在heap上分配内存 提前将内存分块,先是申请一大块内存,然后分配不同大小的小内存。
还采用了缓存的机制进行内存分配
对象的分配是非常高频的操作,小对象占比高,
优化: Balanced GC 优先在G上进行分配。
问题是会导致内存被延迟释放。因此采取移动的方式管理小对象。其实就是分代管理的年轻代管理。
编译器和静态分析
编译器用于识别符合语法和非法的程序,分为分析部分(前端)和综合部分(后端)
静态分析:不执行程序代码,来推导程序行为。
Go编译器优化
为什么要编译器优化:用户无感知,编译后即可获得性能收益
现状:采用优化少
优化思路:场景:长期后端执行任务,用编译时间换更好的效果。
-
函数内联:将调用的函数体的副本替换到调用位置上。
缺点:函数体变大,对cache不友好,生成的Go镜像变大
-
逃逸分析