高性能Go语言发行版优化与落地实现 | 青训营笔记

141 阅读2分钟

这是我参与「第三届青训营 -后端场」笔记创作活动的的第4篇笔记。

1、自动内存管理

  • 动态内存:程序在运行时根据需求动态分配的内存:malloc()
  • 自动内存管理:由程序语言的运行时系统管理动态内存,避免手动管理内存,从而专注于实现业务逻辑;保证内存使用的正确性和安全性。
  • 三个任务:为新对象分配空间;找到存活对象;回收死亡对象的内存空间。

1、1 概念

  • Mutator:业务线程,分配新对象,修改对象指向关系。

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

  • Serial GC:只有一个collector image.png

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

image.png

  • Concurrent GC:mutator和collector同时执行

image.png 注:collector必须感知对象指向关系的改变。

image.png

1、2 追踪垃圾回收

  • 对象被回收的条件:指针指向关系不可达的对象。
  • 标记根对象:如静态变量、全局变量、常量、线程栈等
  • 找到可达对象:求指针指向关系的传递闭包,从根对象出发,找到所有可达对象
  • 清理所有不可达对象:三种算法:Copying GC | Mark-sweep GC | Mark-compact GC

image.png

image.png

image.png

1、3 分代GC

对新生代和老年代指定不同的策略,降低整体内存管理的开销。

  • 新生代:常规的对象分配,由于存活对象少,采用copying GC算法。
  • 老年代:对象一直趋近于活着,反复复制开销大,采用mark-sweep GC算法

1、4 引用计数

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

无法回收环形数据结构。 因为无法确定其起始位置和结束位置。

2、内存分配

内存分块:

  • noscan mspan:GC不需要扫描
  • scan mspan:GC需要扫描 缓存: mcache管理一组mspan

image.png

3、内存逃逸

一个对象本应该分配在栈上面,结果分配在了堆上面,这就是内存逃逸

Golang 中的变量只要被引用就一直会存活,存储在堆上还是栈上由内部实现决定而和具体的语法没有关系。知道变量的存储位置确实和效率编程有关系。如果可能,Golang 编译器会将函数的局部变量分配到函数栈帧(stack frame)上, 然而,如果编译器不能确保变量在函数 return之后不再被引用,编译器就会将变量分配到堆上。而且,如果一个局部变量非常大,那么它也应该被分配到堆上而不是栈上。逃逸分析的好处是为了减少gc的压力。