Go内存管理| 青训营笔记

68 阅读3分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 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
  • 编译器及静态分析
    • 简单介绍
      • 是一个重要的系统软件
      • 识别符合语法和非法的程序
      • 根据不同的系统生成正确高效的代码
      • 词法分析器 -> 语法分析器 -> 语义分析器 -> 中间表示 -> 代码优化 -> 代码生成
    • 静态分析
      • 不执行程序代码 推导程序行为 分析程序性质
      • 控制流 将程序的执行流程 (控制流图)
      • 数据流 将数据推导到控制流上
    • 过程内分析(函数内) 过程间分析(函数调用过程中)
  • Go编译器优化
    • 用编译时间换取更优化的机器码
    • 函数内联
      • 将被调用的函数体的副本替换到调用位置上
    • 逃逸分析
      • 分析代码中的指针作用域 在何处可以被访问
      • 从对象分配处出发 沿着控制流 观察数据流

三、实践练习例子:

这节课会比较偏于理论 实践项目比较少

四、课后个人总结:

通过这节课掌握了一些自动内存管理的基本概念,有哪些自动内存管理的方式等等 在go语言方面掌握了go内存分配的