这是我参与「第五届青训营 」伴学笔记创作活动的第 4 天
程序运行时根据需要动态分配的内存称为动态内存
自动内存管理又称垃圾回收,由程序语言的运行时系统管理动态内存
一、相关概念
1.自动内存管理的重要性:
graph TD
自动内存管理 --> 避免手动内存管理
自动内存管理 --> 保证内存的正确性与安全性
保证内存的正确性与安全性 --> 两次释放同一内存问题
保证内存的正确性与安全性 --> 使用释放后的内存问题
2.自动内存管理的目的:
graph TD
任务 --> 为新对象分配空间
任务 --> 找到存活对象
任务 --> 回收死亡对象的内存空间
3.自动内存管理的分类
在程序运行时有业务线程(Mutator Thread)与GC(Garbage Collection)线程(Collector Thread),GC根据是否支持多个Collector同时回收可分为Serial GC与Parallel GC,这两种GC在执行时,业务线程必须停止,而又有Concurrent GC支持与业务线程同时进行
因此这时候Collectors必须可以感应到对象指向关系的改变。否则,假如对根对象所指的对象全部标记后,又有产生新的对象在这个根对象下,会遗漏标记。
4.自动内存管理的评价层面
graph TD
GC的评价层面 --> 安全性
GC的评价层面 --> 吞吐量:1-t/T
GC的评价层面 --> 暂停时间:STW
GC的评价层面 --> 内存开销
GC的评价层面 --> ...
二、实现方式
1.追踪垃圾回收
1.1基本概念
追踪垃圾回收算法的主要思想是标记根对象,通过根对象找到可到达的对象并标记,删除其他对象。
其中根对象主要包括静态变量、全局变量、常量、线性栈等。
清理时,根据对象的生命周期,采取不同的清理策略。
graph TD
清理方式 --> 标记清理
清理方式 --> 标记复制
清理方式 --> 标记整理
标记清理:将死亡对象内存标记为可分配,下次分配直接覆盖。有效率不稳定,产生过多零碎空间的弊端。
标记复制:将存活对象复制到新的空间,一次性清理原本的空间。有利用率较低的弊端。
标记整理:将存活对象原地整理好。有效率低,浪费空间的弊端。
1.2选择回收方式的策略
分代假说:很多对象分配出来很快就不再使用了。
因此,我们根据经历过垃圾回收的次数对对象标记“年龄”,不同年龄的对象处于Heap的不同区域,以此来降低内存管理的开销。
其中,年轻代存活量很少(大多分配出来使用几次就不需要了),采用标记复制,复制到新的空间。年老代趋向于一直存活,反复移动开销大,采用标记清理,清理死亡对象,存活对象不做处理。
2.引用计数
前面介绍了追踪垃圾回收,现在来讲解第二种回收方式——引用计数
2.1基本概念
每一个对象维护一个被引用数量,当一个对象的被引用数量为0时,清理。
2.2优点与局限性
由于是采用维护引用数目的方式,在程序执行的过程中实现,将内存管理平摊到程序执行的过程中。并且,内存管理不需要了解runtime的实现细节。
但是,维护引用数目增加了空间的开销,并且维护计数开销大。而且也无法回收环形数据结构的对象(有算法优化)。
三、GO内存管理及优化
1.内存管理
1.1分配
Go 先向系统申请一整块内存,再将这块内存分成大块,称为mspan,再将mspan分为特定大小的小块用于分配,根据对象大小选择最合适的块进行分配。mspan根据是否分配包含指针的对象分为scan mspan和noscan mspan,前者GC需要扫描,后者不需要。
1.2缓存
真的写着写着就不知道时间了,一看23点58分了网又断了一会提交的时候0点了,都不算今天的笔记打卡了,明天又有明天的笔记真的......先睡了明天再写剩下的。