这是我参与「第五届青训营」伴学笔记创作活动的第 4 天,通过第四天课程的学习,我学习了go内存管理以及垃圾回收的相关知识,掌握了一些内存机制。以下是我的笔记内容。
一、自动内存管理
主要目的:避免手动管理内存,可以让我们更加专注于逻辑业务的实现,保证内存使用的正确性和安全性。
GC算法:
GC算法不能回收存活的对象,并且GC负责回收堆内存,而不负责回收栈中的内存。
吞吐率:1-GC时间/程序执行总时间
根对象:
根对象是垃圾回收在标记过程时最先检查的对象,它包括全局变量、执行栈(包括栈上的变量及指向分配的堆内存区块的指针)、寄存器。
常用垃圾回收算法(根据对象的生命周期,使用不同的标记和清理策略):
引用计数法:
对每个对象维护一个引用计数,当引用该对象的对象被销毁时,引用计数减1,当引用计数器为0时,回收该对象。
优点:对象可以很好的被回收,不会出现内存耗尽。
缺点:对处理循环的引用不太友好,维护也有一定的代价。
标记清除法:
从根变量开始遍历所有引用的对象,引用的对象标记为“被引用”,没有被标记的进行回收。
优点:解决了引用计数的缺点。
缺点:需要STW(STW可以是Stop the World也可以是Start the World的缩写,指代从Stop the World到Start the World这一动作发生时的一段时间间隔)
分代GC
目的:对年轻和老年的对象,制定不同的GC策略,降低整体内存管理的开销。
二、Go内存管理及优化
分块:
调用系统mmap()向OS申请一大块内存,先将内存划分为大块,之后在划分成特定的大小的小块,用于对象的分配。
优化方案: GAB对于Go内存管理来说是一个对象,本质将多个小对象的分配合并成一次达对象的分配。但是有一个问题:导致内存被延迟释放。那么这个时候就要采用移动GAB中存活的对象来解决,其本质就是用copying GC的算法管理小对象。
三、编译器和静态分析
过程内分析(Intra-procedural analysis):仅在函数内部进行的分析。
过程间分析(Inter-procedural analysis):考虑函数调用时参数传递和返回值的数据流和控制流。
四、Go编译器优化
函数内联:
将被调用函数的函数体的副本替换到调用位置上,同时重写代码来反映参数的绑定。
优点:消除了函数的开销;将过程间分析转化为过程内分析。
缺点:函数体变大,编译生成的Go镜像变大。
Beast Mode:
降低函数调用的开销,增加了逃逸分析。
逃逸分析
逃逸场景:
1.指针逃逸:返回局部变量的指针
2.栈空间不足逃逸
逃逸分析作用:真正做到了按需分配,减小了垃圾回收的压力。
逃逸目的:决定内存分配地址是栈还是堆。
逃逸机制:
- 如果函数外部没有引用,就优先放到栈中;
- 如果函数外部存在引用,就必定放到堆中;
- 如果栈上放不下,必定放在堆中。
五、总结
通过今天的学习,我对go垃圾回收机制更加了解,掌握了三色标记和引用计数法,对逃逸分析也有了一定的了解。继续加油!