垃圾收集器入门

1. GC的由来

C语言是如何清理内存的?

C语言本身是没有提供GC能力的,是程序员通过malloc来获取堆内存,通过free函数来释放内存。

那么让我想想,垃圾回收的执行逻辑跟业务操作是没有关系的。让我联想到“让程序员专注于业务开发“这句话,大师们应该会将垃圾回收这块工作给封装起来,下沉到高级语言的功能包中,于是Java,c++,c#...此类高级语言自带gc功能应运而生。

2. GC的步骤

关于GC,主要有以下步骤

第一步:哪些对象需要回收?
第二步:如何回收?

接下来,我围绕这2个步骤分析,垃圾收集的过程。

2.1 哪些对象需要回收

如果让我来实现这个功能,那么我会怎么做?先标记哪些对象没有被引用了,接着就是回收它。

Jdk标记垃圾对象的方法主要有2种:

这里有2个关键点,面试的时候可能会被问到,

  1. 引用计数法的循环引用问题是什么?
  2. 可达性分析法,GC ROOT有哪些?

2.2 如何回收

JDK是如何回收上述的“垃圾对象”,我们需要考虑以下几个问题:

2.2.1 什么时候回收

我推理,应该有如下二种方式:

2.2.2 使用什么算法回收的

如何判断垃圾回收算法是最好的呢?我理解需要满足以下条件:

我们搞清楚垃圾回收的目标,再看jdk提供的垃圾收集的算法方案,可能会比较好理解点。

标记-清除算法

最简单的,标记完垃圾对象后,直接清除,如下图

标记-清除算法

缺点,从图中可以看出,容易产生内存碎片,不满足2⃣️。

标记-整理算法

解决了标记-清除算法的“内存碎片问题”,在GC后,移动存活对象,整理出连续空闲内存块,如下图

标记-整理算法

缺点,从上述描述中可知,移动存活对象,会引发对象内存地址的变更,存在用户线程与GC回收线程并发访问对象的地址变化冲突问题,JDK提供的解决方案是STW,即暂停用户线程,那么就不满足3⃣️的条件了。

标记-复制算法

也解决了标记-清除算法的“内存碎片问题”,核心思想是将其中内存块(S0),进行垃圾对象的标记,再将存活的对象复制到另一片空白内存中(S0),最后直接清除到S0的整块内存,近似压缩整理碎片空间了。如下图

标记-复制算法

缺点,从上述描述中可知,多占用了一块空白堆内存S1,不满足4⃣️

3. GC的实现产品

太晚了,改天待续...