|
@@ -0,0 +1,96 @@
|
|
|
|
|
+# 垃圾回收算法
|
|
|
|
|
+
|
|
|
|
|
+## 序章
|
|
|
|
|
+
|
|
|
|
|
+GC 是 `Garbage Collection` 的简称, 中文翻译 **垃圾回收**
|
|
|
|
|
+
|
|
|
|
|
+GC 把 程序不用打内存空间 **视为垃圾**
|
|
|
|
|
+
|
|
|
|
|
+GC 要做的两件事情
|
|
|
|
|
+
|
|
|
|
|
+1. 找到内存空间里的垃圾
|
|
|
|
|
+2. 回收垃圾, 让程序员能再次利用这部分空间
|
|
|
|
|
+
|
|
|
|
|
+就 C++ 语言来说申请内存尚不存在什么问题, 但是释放不要的内存空间时就必须一个不漏的释放, 这是非常麻烦的一件事情。如果忘记释放内存, 改内存空间就会发生内存泄漏,即无法使用。如果放任内存泄漏不处理,总有一刻内存会被占满,甚至还可能导致系统崩溃
|
|
|
|
|
+
|
|
|
|
|
+另外,如果释放内存空间时忘记将指向该内存空间的指针设置为 `NULL` 或者 `nullptr` 就会导致指针指向已经被释放的内存空间,处于一种悬挂的状态,称之为 **悬垂指针**。如果程序中错误的引用类悬垂指针,就会产生无法预期的 Bug
|
|
|
|
|
+
|
|
|
|
|
+另外,也有释放错内存空间的可能
|
|
|
|
|
+
|
|
|
|
|
+综上几种情况,可见 GC 的重要性
|
|
|
|
|
+
|
|
|
|
|
+1960年 Jon McCarthy 发布了 **清除算法**
|
|
|
|
|
+
|
|
|
|
|
+1960年 George E. Collins 发布了 **引用计数** 的 GC 算法
|
|
|
|
|
+
|
|
|
|
|
+1963年 Marvin L. Minsky 发布了 **复制算法**
|
|
|
|
|
+
|
|
|
|
|
+现在常用的 GC 算法大多是从上述三种算法中衍生出来的产物
|
|
|
|
|
+
|
|
|
|
|
+GC 更像是一个无名英雄, 默默做着贡献。 但是 GC 基本上是高负载处理, 需要花费一定的时间。当编写动作游戏这样追求即时性的程序时,就必须尽量压低 GC 导致的最大暂停时间。
|
|
|
|
|
+
|
|
|
|
|
+## 基本概念
|
|
|
|
|
+
|
|
|
|
|
+### 头 和 域
|
|
|
|
|
+
|
|
|
|
|
+在 GC 世界中**对象**表示的是 **通过应用程序利益哦那个的数据的集合**
|
|
|
|
|
+
|
|
|
|
|
+对象配置在内存空间里。GC 根据情况将配置好的对象进行**移动**或**销毁**操作
|
|
|
|
|
+
|
|
|
|
|
+一般来说,对象由**头**和**域**构成
|
|
|
|
|
+
|
|
|
|
|
+我们将对象中保存对象本身信息的部分称为 头,一般包括 **对象的大小** 和 **对象的种类** 信息
|
|
|
|
|
+
|
|
|
|
|
+> 知道对象的大小和种类,就能够判断内存中存储的对象的边界
|
|
|
|
|
+
|
|
|
|
|
+此外,头 中事先存有运行 GC 所需的信息,根据算法的不同存储的信息也不同
|
|
|
|
|
+
|
|
|
|
|
+> 比如标记-清除算法中,头 里面就存了一个 falg 用来记录对象是否被标记
|
|
|
|
|
+
|
|
|
|
|
+我们把对象使用者在对象中可访问的部分称为 **域**。可以将其想成C语言中结构体的成员。对象使用者会引用或替换对象的域值,对象使用者基本上无法直接更改**头**的信息
|
|
|
|
|
+
|
|
|
|
|
+域中的数据类型大致分为两种: 指针,非指针
|
|
|
|
|
+
|
|
|
|
|
+指针是只想内存空间中某块区域的值;非指针指的就是编程中直接使用值本身
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+### 指针
|
|
|
|
|
+
|
|
|
|
|
+通过 GC 对象会被销毁或保留。 GC 会根据对象的指针去搜寻其他对象; 另外 GC 对非指针不进行任何操作
|
|
|
|
|
+
|
|
|
|
|
+首先,需要注意语言处理程序是可以辨别指针和非指针
|
|
|
|
|
+
|
|
|
|
|
+另一点,指针是要只想对象的哪部分,如果指针指向对象首地址以外的部分,那么GC就会变得非常复杂。所以大多数语言中,指针都默认指向对象的首地址
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+这里把上图中的 B 和 C 对象称为 A 的字对象, 对某个对象的子对象进行某项处理是 GC 的基本操作
|
|
|
|
|
+
|
|
|
|
|
+### mutator
|
|
|
|
|
+
|
|
|
|
|
+`mutator` 意为 **改变某物** 的意思。说到要改变什么,在 GC 中自然是 GC 对象间的引用关系
|
|
|
|
|
+
|
|
|
|
|
+mutator是垃圾回收机制中的程序执行部分,负责分配、使用和维护对象之间的引用关系。垃圾回收器需要与mutator并行工作,以确保内存的有效管理和回收
|
|
|
|
|
+
|
|
|
|
|
+- 内存分配:当程序需要分配新的内存来存储对象时,mutator负责请求内存分配。它会向垃圾回收器申请一块可用的内存空间,并将对象存储在其中
|
|
|
|
|
+
|
|
|
|
|
+- 内存使用:mutator负责访问和修改分配给它的内存空间中的对象。它可以读取和更新对象的字段、执行方法和算法等
|
|
|
|
|
+
|
|
|
|
|
+- 对象引用:mutator会维护对象之间的引用关系。当一个对象引用另一个对象时,mutator会将引用信息写入内存中的字段或变量。这些引用关系构成了对象图,垃圾回收器根据对象图进行垃圾回收操作
|
|
|
|
|
+
|
|
|
|
|
+### 堆
|
|
|
|
|
+
|
|
|
|
|
+堆 指的是用于动态存放对象的内存空间,当 mutator 申请存放对象时,所需的内存空间就会从这个堆中被分配给 mutator
|
|
|
|
|
+
|
|
|
|
|
+GC 是管理堆中已分配对象的机制。在开始执行 mutator 前, GC 要分配用于堆的内存空间。一但开始执行 mutator,程序就会按照 mutator 的要求在堆中存放对象
|
|
|
|
|
+
|
|
|
|
|
+### 活动对象/非活动对象
|
|
|
|
|
+
|
|
|
|
|
+将分配到内存空间中的对象中那些能够通过 mutator 引用的对象称为 **活动对象**;反之不能通过程序引用的对象称为 **非活动对象**
|
|
|
|
|
+
|
|
|
|
|
+非活动对象就是我们说的 垃圾
|
|
|
|
|
+
|
|
|
|
|
+GC 会保留活动对象,销毁非活动对象。当销毁非活动对象时,其原本占据的内存空间会得到解放,供下一个要分配的新对象使用
|
|
|
|
|
+
|
|
|
|
|
+
|