Go 语言内存管理详解| 青训营笔记

174 阅读3分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 5 天

【后端专场 学习资料二】第五届字节跳动青训营 - 掘金

学习内存管理优化编译器优化

隔离:通过配置选项控制是否开启优化 可观测:必要的日至输出 文档:做了什么,没做什么,达到什么效果。这样用户知道是否要开启优化

自动内存管理

  • concurrently
  • mutator thread:业务线程(比如 goroutine)
  • Collector: GC 线程
  • serial GC 只有一个 collector
  • Concurrent GC: 并发 GC (nutator 和 collector 可以同时执行)
  • Parallel GC: 并行 GC(多个 collector, 但 mutator 和 collector 不同时执行)
    • collector 必须感知对象指向关系的改变,否则就会出错

暂停就是 StopTheWorld

并发:一个cpu 轮流切换多个线程 并行:多个 cpu 同时执行多个线程

GC 算法

评价 GC 算法

  • 安全性
  • 吞吐率
  • 暂停时间
  • 内存开销 推荐书:《the garbage collection handbook》

介绍 2 种垃圾回收算法:

追踪垃圾回收

回收条件:不可达的对象 清理方式:

  • copying GC
  • mark-sweep GC
  • mark-compact GC

如何选择策略:根据对象生命周期,选择不同的标记和清理策略

分代 GC

分代假说:很多 young 刚分配就结束生命周期 根据对象的年龄,放在 heap 不同区域,制定不同 GC 策略

  • 年轻代可使用 copying GC
  • 老年代可使用 mark-sweep GC

引用计数

GCROOT 优点:

  • 内存管理操作被分摊到程序执行过程中
  • 不需要了解 runtime 的实现细节(比如 C++智能指针) 缺点:
  • 维护计数开销大:原子操作计数
  • 无法回收环形数据结构 weak reference
  • 内存开销:额外空间存储引用计数
  • 回收内存时可能引发暂停(回首大数据结构时,需要多时间,所以会引起暂停)

内存分配

分块

nonscan mspan:分配不包含指针对象,GC 不用扫描 scan mspan:分配包含指针对象,GC 需要扫描

缓存

TCMalloc

优化

小对象多 分配路径过长 根据以上 2 个问题开发 Balance GC

Balance GC

本质:多个小对象分配,合并成一次大对象分配 问题:GAB 的分配方式导致内存延迟释放

  • 解决方法:copying GC 算法,复制到另外 GAB 中

编译器优化

静态分析

不执行代码 控制流 control flow 数据流 data flow

  • 过程内分析:仅在函数内
  • 过程间分析:考虑函数调用时参数传递和返回值

函数内联

将过程间分析转换成过程内分析 缺点:

  • 函数体变大,instruction cache (icache) 不友好。会频繁 icache miss
  • Go 镜像变大

Beast Mode: go 语言特性interface、defer 等限制了函数内联 beast mode:

  • 调整内联策略,使更多函数被内联。
  • 增加了其他优化的机会:逃逸分析

逃逸分析

分析代码中指针的动态作用域 函数内联扩展了函数边界,更多对象不逃逸。这样未逃逸对象可以在栈上分配