初始Go语言(4)——Go语言内存管理| 青训营笔记

94 阅读4分钟

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

本文是对于掘金课程的课程笔记,针对课程内容的一些重难点、本人在学习Go语言内存管理进行的简单记录。本次课程内容偏向于理论分析,因此没有进行相关实践分析

一、本堂课的重点内容

  1. 自动内存管理
  2. Go内存管理及优化
  3. 编译器和静态分析
  4. Go编译器优化

二、详细知识点介绍

性能优化

性能优化是什么?

提升软件系统处理能力,减少不必要消耗,降低成本,发掘计算机算力

为什么要性能优化?

提升用户体验

资源高效利用,降低成本,提高效率

性能优化的几个层面:

业务层优化:优势在于可以针对特定场景,具体问题具体优化,可以获得较大的性能收益

语言运行时优化:可以解决更加通用的问题,但是需要考虑更多的场景

数据驱动:在进行优化时是以数据为驱动的,我们可以使用前面学到的pprof工具进行自动化的性能分析,在优化时需要注意首先优化最大性能瓶颈

自动内存管理

  • 动态内存
  • 自动内存管理(垃圾回收机制)
  • 三个任务:为新对象分配空间;找到存活对象;回收死亡对象的内存空间
  • 内存管理相关概念

Mutator:业务线程,分配新对象

Collector:GC线程,找到存活对象,回收死亡对象的内存空间

Serial GC:只有一个collector

Parallel GC:支持多个collecotrs同时回收的GC算法

Concurrent GC:mutator 和 collecotr可以同时执行

评价GC算法的几个指标: 安全性(基本要求);吞吐率(GC用时);暂停时间(业务是否感知);内存开销(GC元数据开销)

追踪垃圾回收

  • 对象被回收条件:关系不可达
  • 标记根对象
  • 标记:找到可达对象
  • 清理:不可达对象

分代GC

  • 年轻代:常规对象分配;由于存活对象少,采用copying colleciton;GC吞吐率高
  • 老年代:趋向于一直活着,复制开销大,可以采用mark-sweep collection

Go内存分配

  • 分块:为对象在heap上分配内存,提前将内存分块,然后根据对象的大小,选择最适合的块返回
  • 缓存:快速分配,每个p包含一个mcache用于快速分配,mcache管理一组mspan,分配完毕后向mcentral申请,如果mspan没有分配对象,mspan缓存在mcentral中而不是立即释放

Go内存管理优化

使用Balanced GC

每个g都绑定一大块内存,成为GAB,用于noscan类型小对象分配,使用三个指针(base,end,top)进行维护,使用Bump pointer风格对象分配

image.png

编译器和静态分析

  • 前端(分析部分):词法分析,语法分析,语义分析,中间代码生成
  • 后端(综合部分):代码优化,代码生成

静态分析:

  • 静态分析:不执行程序代码,推导程序行为,分析程序性质
  • 控制流:程序执行流程
  • 数据流:数据在控制流上的传递
  • 过程内分析:仅在函数内部分析
  • 过程间分析:考虑函数调用的参数传递和返回值的数据流和控制流

Go编译器优化

  • 函数内联:将调用函数的函数体的副本替换到调用位置上,重写代码以反映参数绑定,将过程间分析转为过程内分析
  • Beast Mode:调整函数内联策略

三、课后个人总结

学习Go语言的内存管理让我联想到了Java的内存分配,尤其是GC部分,有许多相通之处,例如年轻代与老年代的划分;引用计数机制;垃圾回收的算法等等。将各类语言的各种特性比较分类,也是学习新编程语言的好方法。