这是我参与「第五届青训营 」笔记创作活动的第4天
性能优化的层面
业务层优化
- 针对特定业务场景
- 容易获得较大优化收益
语言运行时优化
- 解决更通用的性能问题
- 考虑更多场景
- Tradeoffs
数据驱动
- 自动化性能分析工具-pprof
- 依靠数据而非猜测
- 首先优化最大瓶颈
自动内存管理
背景
-
动态内存:程序在运行时根据需求分配的内存:
malloc() -
自动内存管理(垃圾回收): 由程序语言的运行时系统管理动态内存
- 保证内存使用的安全性与正确性
- 避免手动内存管理
-
三个任务
- 为新对象分配空间
- 找到存活对象
- 回收死亡对象的内存空间
-
基本概念
- Mutator : 业务线程,分配新对象,修改对象指向关系
- Collector : GC线程,找到存活对象,回收死亡对象的内存空间
- Serial GC : 只有一个collector的GC算法
- Parallel GC : 支持多个collectors同时回收的GC算法
- Concurrent GC : mutator(s)和collector(s)可以同时执行的GC算法
- 关于Concurrent GC的难点:
GC前: O.x指向a
GC过程: 将O,a都标记未存活,但是由于业务线程存活,有可能之后出现一个b被o.y指向 ,所以这是算法的难点
垃圾回收算法
垃圾是指程序向堆栈申请的内存空间,随着程序的运行已经不再使用这些内存空间,这时如果不释放他们就会造成垃圾也就是内存泄漏。
Go中的栈上内存仍由编译器负责管理回收,而堆上的内存由编译器和垃圾收集器负责管理回收。
引用计数算法
每个对象维护一个引用计数,当被引用对象被创建或被赋值给其他对象时引用计数自动 +1。如果这个对象被销毁,那么计数-1,当计数为0时,回收该对象
优点:对象可以很快被回收,不会出现内存耗尽或者达到阈值才回收
缺点:不能很好的处理循环引用
标记-清除((Tracing GC) (go1.3)
从根变量开始遍历所有引用的对象,引用的对象标记“被引用”,没有标记的则进行回收
清理策略:
- 将存活对象复制到另外空间:copying gc
- 将死亡对象的内存标记为可分配:Mark-sweep GC,通过free list管理空闲内存
- 移动并整理存活对象:Mark-compact GC,原地整理对象
优化:先停止STW,再进行垃圾清除
优点:解决了引用计数的缺点
缺点:需要STW(stop the world),暂停程序运行、
分代GC(Generation GC)
-
分代假说
-
分配后很快不再使用
-
每个对象由年龄:经过GC的次数
-
对年轻和年老对,制定不同GC策略
-
不同年龄对象处于heap不同区域
-
年轻代
- 常规的对象分配
- 由于存活对象很少,可以使用copying gc
- GC吞吐率高
-
老年代
- 对象趋向于一直活着,反复复制开销较大
- 可以采用mark-sweep collection