这是我参与「第五届青训营 」伴学笔记创作活动的第 4 天
一、本堂课重点内容:
- 自动内存管理
- go内存管理及优化
- 编译器和静态分析
- Go编译器优化
二、详细知识点介绍:
- 性能优化 基本
- 提升软件系统处理能力 减少不必要消耗
- 提升用户体验
- 高效利用资源
- 业务层方面与语言运行时的优化
- 自动内存管理
- 由程序语言运行时的系统管理动态内存
- 避免手动内存管理
- 保证内存使用正确性及安全性
- 为新的对象分配空间(Mutator)
- 找到存活对象 回收死亡对象空间(Collector)
- Concurrent GC (Mutator 与 Collector 同时执行) 必须感知对象关系的改变
- 追踪垃圾回收
- 对象被回收条件:指针指向关系不可达的对象
- 标记根对象(静态变量、全局变量、常量等)
- 标记可达对象
- 清理不可达对象
- 将存活对象复制到另外的内存空间(copying GC)
- 将死亡对象标记为可分配(Mark-sweep GC)
- 移动并整理存活对象(Mark-compact GC)原地整理对象
- 根据对象生命周期 使用不同的标记和清理策略
- 分代 GC
- 假设大多数的对象被分配出来后 很快就会被清理
- 每个对象都有年龄 大小为经历过GC的次数
- 年轻和老年的对象制定不同的GC策略
- 年轻采用 copying 吞吐率高
- 老年采用 mark-sweep 因为一直存在 不需要反复移动内存
- 引用计数
- 每个对象都有关联的引用数目
- 对象存活的条件:引用数 > 0
- 缺点:维护计数的开销大 无法回收环形数据结构 回收内存时也可能会stw
- 由程序语言运行时的系统管理动态内存
- Go内存管理及优化
- 内存分配 为对象在heap中分配内存
- g -> m -> p -> mcache -> mspan -> mcentral -> memory block -> return
- 1.分块
- 调用系统调用mmap() 向OS申请一大块内存 例如4MB
- 将内存划分成大块 例如8KB 称作mspan
- 再将大块划分成特定大小的小块用于对象分配
- noscan mspan 分配不包含指针的对象 GC不需要扫描
- scan mspan 分配包含指针的对象 GC需要扫描
- 根据对象的大小 选择最合适的块返回
- 2.缓存
- 在GMP中 每个p包含一个mcache用于快速分配 为绑定在g上的p分配对象
- mcache管理一组mspan
- 当管理的mspan分配完毕时 再向mcentral中申请mspan
- mspan中没有对象时 不会返回给OS 而是先缓存在mcentral中
- 每秒会分配GB级别的对象 绝大多数的对象都是小对象
- 优化方案 Balanced GC
- 每个g都绑定一大块内存(1KB) 称作goroutine allocation buffer (GAB)
- GAB用于分配小对象 < 128B
- 使用三个指针维护GAB base(基础地址) top(已分配地址) end(结束边界地址)
- 使用指针碰撞来分配
- 本质:将小对象的分配转化为大对象的分配
- 问题:其中一个小对象的延迟释放会导致大对象的延迟释放 从而浪费内存
- 解决:将小对象移动到其他的GAB 组合多个小对象 释放原来的GAB
- 内存分配 为对象在heap中分配内存
- 编译器及静态分析
- 简单介绍
- 是一个重要的系统软件
- 识别符合语法和非法的程序
- 根据不同的系统生成正确高效的代码
- 词法分析器 -> 语法分析器 -> 语义分析器 -> 中间表示 -> 代码优化 -> 代码生成
- 静态分析
- 不执行程序代码 推导程序行为 分析程序性质
- 控制流 将程序的执行流程 (控制流图)
- 数据流 将数据推导到控制流上
- 过程内分析(函数内) 过程间分析(函数调用过程中)
- 简单介绍
- Go编译器优化
- 用编译时间换取更优化的机器码
- 函数内联
- 将被调用的函数体的副本替换到调用位置上
- 逃逸分析
- 分析代码中的指针作用域 在何处可以被访问
- 从对象分配处出发 沿着控制流 观察数据流
三、实践练习例子:
这节课会比较偏于理论 实践项目比较少
四、课后个人总结:
通过这节课掌握了一些自动内存管理的基本概念,有哪些自动内存管理的方式等等 在go语言方面掌握了go内存分配的