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

114 阅读3分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 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点了,都不算今天的笔记打卡了,明天又有明天的笔记真的......先睡了明天再写剩下的。