GC的定义
- GC是Garbage Collection的简称,中文称为“垃圾回收”。
GC要做的两件事
- 找到内存中空间里的垃圾
- 回收垃圾,让程序员再次利用这部分空间
GC的历史
- GC有着非常久远的历史,最初的GC算法是John McCarthy在1960年发布的。
GC标记-清除算法
- Jhon McCarthy身为Lisp之父和人工智能之父,事实上同时也是GC之父。
GC引用计数算法
- Georage E.Collins在论文中发布了叫作引用计数的GC算法
GC复制算法
- “人工智能之父”之称的Marvin L.Minsky在论文中发布了复制算法。
学习GC之前
1.1 对象/头/域
- 在GC的世界中,对象表示的是"通过应用程序利用的数据集合。对象配置在内存空间里,GC是根据情况将配置好的对象进行移动或销毁操作,因此对象是GC的基本单位。
- 一般来说,对象是由头(header)和域(field)构成。
1.1.1 头
- 对象头中主要包含以下信息,对象的大小,对象的种类。
- 如果不清楚对象的大小和类型,就无法判别内存中的存储对象的边界。
- 头中实现存有运行GC所需要的信息。根据GC算法不同,信息也不同。
1.1.2 域
-
我们把对象使用者能访问到的部分称为“域”。对象使用者会引用或替换对象的域值。另一方面对象使用者几乎无法直接更改头的信息。
-
域中的数据类型大致为两种:
- 指针
- 非指针
指针是指向内存空间中某块区域的值。 非指针是在编程中直接使用值本身,数值,字符以及真假值都是非指针。
1.2 指针
- GC是根据对象的指针搜寻其他对象。另一方面,GC对非指针不进行任何操作。
- 注意:
- 语言处理程序需要能够判别是否是指针。如何判别之后再提。
- 一般指针默认指向对象的首地址。如果指向对象首地址以外的地址那么GC会变得非常复杂。
1.3 mutator
- mutator是Edsger Dijkstra琢磨出来的词,有“改变某物”的意思。改变的是GC对象之间的引用关系。用一句化概括,它的实体就是“应用程序”。GC就是在这个mutator内部精神饱满地工作者。
- matator有以下两种操作
- 生成对象
- 更新指针
1.4 堆
- 堆指的是用于动态存档对象的内存空间。当应用程序申请存放对象时,所需要的内存空间就会在这个堆上分配。
1.5 活动对象/非活动对象
- 我们将分配到内存空间中的对象中那些能通过应用程序引用的对象称为“活动对象”,不能引用到的为“非活动对象”。非活动对象因为没人可以搭理,所以被称为“垃圾”。
- 非活动对象不会重新成为活动对象。mutator只会重写申请空间。
1.6 分配
- 分配指的是在内存空间中分配对象。当mutator需要新的对象时,就会像分配器申请一个大小合适的空间。之后我们会讲到多大是合适的空间。
1.7 分块
- 分块在GC的世界里指的是为利用对象而事先准备好的空间。
- 初始时堆被一个大分块占据。mutator向分配器申请空间时,分块就会被分割一个合适的大小给对象。
1.8 根
- 在GC的世界里,根是指向对象的指针的“起点”部分。
a = new Object()
a.field1 = new Object()
//全局变量a在引用程序中可以访问到所以是活动对象,
//此外通过a的field1的引用到的对象也是活动对象。调用栈,寄存器以及全局变量空间都是根。
1.9 评价标准
1.9.1 吞吐量
- 吞吐量指的是“在单位时间内的处理能力”,这点在GC的世界中也不例外。
- 判断个算法吞吐量的好坏时不能一概而论。打个比方,复制算法和标记算法相比,活动对象越少吞吐量越高。这是因为GC复制算法只检查活动对象,而GC标记算法则会检查所有的活动和非活动对象。
- 然后随着活动对象的增多,各GC算法表现出的吞吐量也会相应改变。极端情况下,甚至会出现标记算法比复制算法吞吐量更高的情况。
1.9.2 最大暂停时间
- 最大暂停时间指的是“因执行GC而暂停的mutator的最长时间”。较大的吞吐量和较短的暂停时间不可兼得。所以应根据执行的应用程序所重视的指标不同,来选择不同的GC算法。
1.9.3 堆得使用
- 根据GC算法的差异,堆使用效率也大相径庭。左右堆使用效率的因素有两个:
- 头的大小
- 堆得用法