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

43 阅读3分钟

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

学习内容

今天学习了go的内存管理优化以及编译器优化。

性能优化

提升软件系统的处理能力,减少不必要的消耗,充分发掘计算机算力。

  • 提升用户体验;
  • 资源高效利用,降低成本。

软件质量至关重要

  1. 保证接口稳定
  2. 测试用例:覆盖尽可能多的场景,方便回归
  3. 写文档
  4. 隔离:通过选项控制优化是否开启
  5. 客观性:必要的日志输出

自动内存管理

自动内存管理(垃圾回收),由程序语言的运行时系统管理动态内存,保证内存使用的正确性、安全性。

三个任务

  • 为新对象分配空间
  • 找到存活对象
  • 回收死亡对象的内存空间

一些概念

  • Mutator:业务线程,分配新对象,修改对象指向关系
  • Collector:GC线程,找到存活对象,回收死亡对象的内存空间
  • Serial GC:只有一个collector
  • Parallel GC:支持多个collectors同时回收的GC算法
  • Concurrent GC:mutator和collector可以同时执行

评价GC算法

  • 安全性:不能回收存活对象
  • 吞吐率:花在GC上的时间
  • 暂停时间:业务是否感知
  • 内存开销:GC元数据开销

追踪垃圾回收

对象回收条件:指针指向关系不可达的对象
三个步骤:

  1. 标记根对象,包括静态变量、全局变量、常量和线程栈等;
  2. 标记可达对象,从根对象出发,找到所有可达对象;
  3. 清理所有不可达对象:Coping GC、Mark-sweep GC和Mark-compact GC。

引用计数

每个对象都有一个与之关联的引用数目,当且仅当引用数大于0时对象存活。

Go的内存管理及优化

为对象在heap上分配内存

在Go中会提前将内存分块:

  • 调用系统调用mmap()向OS申请一大块内存;
  • 先将内存划分为大块,称为mspan;
  • 再将大块继续划分为特定大小的小块用于对象分配;
  • noscan mspan:分配不包含指针的对象;
  • scan mspan:分配包含指针的对象。

根据对象大小,选择合适的块返回。

缓存:TCMalloc

捕获.PNG

Go内存管理优化

Balanced GC:

  • 每个g都绑定一大块内存(1KB)GAB
  • GAB用于noscan类型的小对象分配(<128 B)
  • 使用三个指针维护GAB,base、end和top
  • Bump pointer(指针碰撞)风格对象分配:无信仰和其他分配请求互斥;分配动作简单高效。

以上针对一个小对象的内存分配,将多个小对象的分配合成一次大对象的分配。
问题:导致内存被释放延迟
方案:移动GAB中存活的小对象

编译器优化

编译器

捕获.PNG

静态分析

不执行程序代码,推导程序的行为,分析程序的性质。

  • 控制流:程序执行的流程
  • 数据流:数据在控制流上的传递
  • 过程内分析
  • 过程间分析

Go的编译器优化

函数内联

将被调用函数的函数体的副本替换到调用位置上,同时重写代码以反映参数的绑定。

逃逸分析

分析代码中指针的动态作用域:指针在何处可以被访问。