写在前面
本文是对课程学习中关于Go内存管理和性能优化相关知识的记录,包括性能优化的基本问题、自动内存管理的基本概念和基本流程以及在内存管理中用到的技术等。
自动内存管理相关概念
自动内存管理理论概念偏多,有一些特定的概念需要进行了解。下面介绍一些自动内存管理中相关的概念
- 动态内存
- 动态内存是指在程序的运行过程中根据程序的运行时需要进行内存的分配
- 比如malloc函数就是在运行时进行内存申请
- 垃圾回收机制
- 垃圾回收机制是指由程序在运行时系统回收动态内存
- 比如malloc的内存在不需要时进行free
- 替代了程序员进行内存释放,使得程序员能够将更多的精力放在业务逻辑的实现
- 避免了一些内存泄漏问题
- 一些概念
- Mutator是业务线程,用来分配新对象,修改对象指向关系
- Collector是GC线程,用来寻找存活对象、回收内存
- Serial GC指只有一个collector的情况
- Parallel GC指多个collector的情况
- Concurrent GC指并行执行的情况
- 追踪垃圾回收
- 在整个追踪垃圾回收的过程中,我们通过指针指向来判断对象的依赖关系,当一个对象无法通过指针指向到达,则说明该对象是需要被回收的
- 首先我们应该标记初始对象,也就是根对象,然后程序运行过程中通过指针的指向进行标记,那么所有的可达对象就会通过指针关系被标记到
- 在清理所有不可达对象的过程中,需要将存活的对象移到另外的内存空间,然后将死亡对象所占用的空间标记为可以被分配的,最后整理尚存活的对象
- 需要注意的是,不同对象的生命周期是不一样的,这可以根据写程序时变量的作用域理解,对于生命周期不同的对象不能一视同仁,需要进行不同的策略。
- 分代GC
- 在程序运行过程中有很多的对象在分配之后就不会使用了,这就是分代假说,根据该理论,每一个对象都有年龄,我们根据对象的年龄进行不同的GC策略,能够提高内存管理的效率。
- 对于年轻的对象使用copying collection策略比较好
- 对于年老的对象使用mark-sweep collection策略比较好
- 引用计数
- 对于判断对象的存活,除了通过对象是否可达判断,还可以通过引用计数技术来判断
- 这项技术在C++中体现为智能指针
- 对于引用计数,如果对象的引用计数为0.那么我们认为对象不再存活
- 但引用计数具有额外内存开销、维护开销大等缺点
Go内存管理
- 内存分配
- 分块
- 需要在堆上进行内存的分配。首先要像操作系统申请一大块内存
- 然后需要将分配的一大块内存进行划分
- 然后在为对象分配内存时,根据对象的大小选择合适的内存块返回
- 缓存
- mcache用于管理一组mspan,通常小对象是在mcache中分配的,大对象是从mheap分配的
- mcache的mspan分配完毕之后会需要向mcentral申请
- mspan无分配对象时,会缓存在吗central中
- 存在的问题: 内存分配耗时、小对象占比高
- 优化方案:使用Balanced GC进行优化,使用指针碰撞风格的对象分配等等
- 分块
总结
内存管理对于开发人员来说是透明的,就像OS的底层对用户是透明的一样。内存管理能够帮助开发人员将更多的精力放在业务开发上,但是了解内存管理的底层逻辑能够帮助我们写出更加高效的代码,对代码质量的提高是有帮助的。