这是我参与「第五届青训营 」伴学笔记创作活动的第 3 天
这里是GO中GC,内存管理&优化,Go中的编译器和静态分析等。
Brief Introduction
什么是性能优化?提升软件处理能力,减少不必要的消耗。
用户体验更好,资源高效利用,降低成本的同时,提高效率。(小的优化 x 海量机器 = 显著性能提升)
-
性能优化层面:
-
业务代码(业务层优化)
- 特定场景,具体问题,具体分析
- 容易获得较大性能收益
-
SDK(语言运行时优化)
- 解决更通用的性能问题
- 考虑更多通用场景
- Tradeoffs
-
基础库
-
语言运行时
-
OS
-
太底层,好像也可以优化,但是目前没有做昂!!!
-
数据驱动优化:
- 工具-pprof
- 依靠数据而非猜测
- 首先优化最大瓶颈
SDK很重要哇,保证接口稳定的前提下稳定。存在接口特定行为,就会有用户依赖行为,轻易改变会有很多问题!!!(tricks)
-
课程目录:
- 自动内存管理
- Go内存管理以及优化
- 编译器和静态分析
- Go编译器优化
自动内存管理
管理的是动态内存:
- 程序在运行的时候,根据需求动态分配的内存:malloc()
自动内存管理(垃圾回收): 程序语言,运行时系统管理动态内存
- 避免手动内存管理,专注业务逻辑
- 保证内存管理正确性和安全性:double-free problem, use-after-free problem
三个任务:
- 为新对象分配空间
- 找到存活对象
- 回收死亡对象的内存空间
相关概念
感觉在哪里看到过......《深入理解Java虚拟机》
相关概念:Stop The World
- 评价GC算法:
追踪垃圾回收
-
回收条件:指针指向不可达
-
步骤:
-
标记根对象
- 静态变量、全局变量、常量、线程栈等(必然存活的对象)
-
标记:找到所有可达对象
- 根据指针找到所有可达的对象(求指针指向关系的传递闭包)
-
清理:所有不可达对象
- Copying GC(存活对象复制到别的地方)
- Mark-sweep GC(死亡对象内存标记为“可分配”)
- Mark-compact GC(移动并整理存活对象)
-
-
根据对象生命周期,使用不同的标记和清理策略
- copying GC:
- Mark-sweep GC:
- Mark-compact GC:
和copying不同,Compact GC: 原地整理对象
分代GC
年轻Copy开销少,老年Mark-sweep/Mark-compact开销少
引用计数
-
每个对象有一个与之关联的引用数目
-
对象存活条件:当且仅当引用数大于0
-
优点:
- 内存管理平摊到程序执行过程中
- 内存管理不需要了解runtime的实现细节:C++智能指针(smart pointer)
-
缺点:
- 维护开销大,原子操作保证对引用计数操作的原子性和可见性
- 环形数据结构无法回收 --- weak reference
- 内存开销:每个对象引入了额外的内存空间存储引用数目
- 回收内存时依然可能引发暂停
红色:自己引用自己,环形,无法回收。
Null:一个为null,它指向的所有的都要回收了,不可避免,大对象回收可能就是要暂停昂!!!
Summary
Go内存管理及优化
分配
分块
目标:为对象在heap上分配内存
提前将内存分块
缓存
管理优化
- 内存分配特点:
字节跳动优化方案:Balanced GC
每个Goroutine提前给一块儿,能快速分配内存昂!!!
- What is GAB
- GAB tricks:
其实每个GAB底层还是以1KB的对象来管理的,如果一个大的GAB中,一个小的对象没有被回收,那么整个GAB就不应该被回收昂 -> 内存的延迟释放。
- 性能收益:
上面是Balanced GC开启之前的性能,下面是开启之后的性能优化。
编译器和静态分析
基本介绍
- 编译器:
- 静态分析:
- 过程内和过程间分析:
Go编译器优化
函数内联
- 概念:
-
缺点:
- 函数体变大,instruction cache(icache)不友好
- 编译生成的Go镜像变大(函数复制了很多份)
-
函数内联在大多数情况下是正向优化
-
内联策略:
- 调用和被调函数的规模
- ......
Beast Mode
逃逸分析
- 性能收益:
Summary
References
- The Garbage Collection Handbook,可以康康很多的概念&算法昂,英文版写的非常好,可以读读英文版昂!!!
- references
- 掘金对应课程笔记:juejin.cn/post/718952…