Go自动内存管理 | 青训营笔记

105 阅读6分钟

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

这里是GO中GC,内存管理&优化,Go中的编译器和静态分析等。

Brief Introduction

什么是性能优化?提升软件处理能力,减少不必要的消耗。

用户体验更好,资源高效利用,降低成本的同时,提高效率。(小的优化 x 海量机器 = 显著性能提升)

  • 性能优化层面:

    • 业务代码(业务层优化)

      • 特定场景,具体问题,具体分析
      • 容易获得较大性能收益
    • SDK(语言运行时优化)

      • 解决更通用的性能问题
      • 考虑更多通用场景
      • Tradeoffs
    • 基础库

    • 语言运行时

    • OS

太底层,好像也可以优化,但是目前没有做昂!!!

  • 数据驱动优化:

    • 工具-pprof
    • 依靠数据而非猜测
    • 首先优化最大瓶颈

image-20230115160343923

SDK很重要哇,保证接口稳定的前提下稳定。存在接口特定行为,就会有用户依赖行为,轻易改变会有很多问题!!!(tricks)

  • 课程目录:

    • 自动内存管理
    • Go内存管理以及优化
    • 编译器和静态分析
    • Go编译器优化

自动内存管理

  • 管理的是动态内存:

    • 程序在运行的时候,根据需求动态分配的内存:malloc()
  • 自动内存管理(垃圾回收): 程序语言,运行时系统管理动态内存

    • 避免手动内存管理,专注业务逻辑
    • 保证内存管理正确性安全性:double-free problem, use-after-free problem
  • 三个任务:

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

相关概念

image-20230115162852245

image-20230115162821277

感觉在哪里看到过......《深入理解Java虚拟机》

相关概念:Stop The World

  • 评价GC算法:

image-20230115162956124

追踪垃圾回收

  • 回收条件:指针指向不可达

  • 步骤:

    • 标记根对象

      • 静态变量、全局变量、常量、线程栈等(必然存活的对象)
    • 标记:找到所有可达对象

      • 根据指针找到所有可达的对象(求指针指向关系的传递闭包)
    • 清理:所有不可达对象

      • Copying GC(存活对象复制到别的地方)
      • Mark-sweep GC(死亡对象内存标记为“可分配”)
      • Mark-compact GC(移动并整理存活对象)
  • 根据对象生命周期,使用不同的标记和清理策略

image-20230115163417399

  • copying GC:

image-20230115163434885

  • Mark-sweep GC:

image-20230115163500876

  • Mark-compact GC:

image-20230115163524385

和copying不同,Compact GC: 原地整理对象

分代GC

image-20230115163626913

image-20230115163738993

年轻Copy开销少,老年Mark-sweep/Mark-compact开销少

引用计数

  • 每个对象有一个与之关联的引用数目

  • 对象存活条件:当且仅当引用数大于0

  • 优点:

    • 内存管理平摊到程序执行过程中
    • 内存管理不需要了解runtime的实现细节:C++智能指针(smart pointer)

image-20230115164213775

  • 缺点:

    • 维护开销大,原子操作保证对引用计数操作的原子性和可见性
    • 环形数据结构无法回收 --- weak reference
    • 内存开销:每个对象引入了额外的内存空间存储引用数目
    • 回收内存时依然可能引发暂停

image-20230115164246742

红色:自己引用自己,环形,无法回收。

Null:一个为null,它指向的所有的都要回收了,不可避免,大对象回收可能就是要暂停昂!!!

Summary

image-20230115164850303

Go内存管理及优化

分配

分块

目标:为对象在heap上分配内存

提前将内存分块

image-20230115165223380

缓存

image-20230115165446062

管理优化

  • 内存分配特点:

image-20230115165556011

image-20230115165618071

image-20230115165804327

字节跳动优化方案:Balanced GC

每个Goroutine提前给一块儿,能快速分配内存昂!!!

  • What is GAB

image-20230115170033419

  • GAB tricks:

image-20230115170332311

其实每个GAB底层还是以1KB的对象来管理的,如果一个大的GAB中,一个小的对象没有被回收,那么整个GAB就不应该被回收昂 -> 内存的延迟释放。

  • 性能收益:

image-20230115170504395

上面是Balanced GC开启之前的性能,下面是开启之后的性能优化。

编译器和静态分析

基本介绍

  • 编译器:

image-20230115170749951

  • 静态分析:

image-20230115171002490

  • 过程内和过程间分析:

image-20230115171122913

Go编译器优化

image-20230115171244499

函数内联

  • 概念:

image-20230115171419016

image-20230115171514901

  • 缺点:

    • 函数体变大,instruction cache(icache)不友好
    • 编译生成的Go镜像变大(函数复制了很多份)
  • 函数内联在大多数情况下是正向优化

  • 内联策略:

    • 调用和被调函数的规模
    • ......

Beast Mode

image-20230115172729499

逃逸分析

image-20230115172921044

  • 性能收益:

image-20230115173009639

Summary

image-20230115173210251

References

  1. The Garbage Collection Handbook,可以康康很多的概念&算法昂,英文版写的非常好,可以读读英文版昂!!!
  2. references

image-20230115174433332

  1. 掘金对应课程笔记:juejin.cn/post/718952…