前言

由于我们之前学过了JVM的垃圾回收机制以及JVM如何判断一个垃圾对象,所以在这里我有必要讲一下几种垃圾收集算法和几种垃圾收集器,首先为什么会有不同的垃圾收集算法呢?因为随着我们的发展,我们的业务出现多种多样的情况,有些业务需要内存比较大,有些业务需要垃圾收集的时间比较短,所以针对不同的业务我们要使用不同的垃圾收集算法,而不同的垃圾收集算法我们又封装成不同的垃圾收集器,接下来我就简单来讲解一下这几种垃圾收集算法和垃圾收集器。

垃圾收集算法——复制算法

垃圾收集器以及垃圾收集算法_java

垃圾收集器以及垃圾收集算法_面试_02

通过上面图片我们可以简单看出复制算法是将整个内存先分为两块内存区域N1和N2,使用的时候只使用其中一块,另一块为空,当我们要进行垃圾回收时,就将N1中的存活对象复制到N2中,然后再将N1清空,所以下一次垃圾回收时会将N2的存活对象复制到N1,然后将N2清空,所以这种算法我们可以看到效率比较高,但是浪费了一半的内存没有进行使用。

垃圾收集算法——标记清除

垃圾收集器以及垃圾收集算法_算法_03

垃圾收集器以及垃圾收集算法_jvm_04

标记清除算法与复制算法不同的就是使用了一整块内存,这样的话内存大小就比复制算法大一倍,但是我们现在假如有一个两个大小的对象并排要进入内存中我们就会发现无法进入,因为在垃圾收集之后每一行都有一个对象,我们只能放入两个大小为1的对象,而不能放一个大小为2的对象,如下图

垃圾收集器以及垃圾收集算法_算法_05

所以因为我们要放入的对象比较大,即便是内存剩余总空间大小够我们要放入的对象大小,但是没有连续的空间能够来放我们的对象,接下来就要有一种算法解决这种问题。

垃圾收集算法——标记整理

垃圾收集器以及垃圾收集算法_算法_03

垃圾收集器以及垃圾收集算法_程序人生_07

这种算法就是在清除了垃圾对象后将存活对象按照顺序从头开始存储,这样就可以留出来连续空间用来存储大的对象了。

垃圾收集算法——分代收集理论

垃圾收集器以及垃圾收集算法_算法_08

这里我们要重点说一下分代收集算法,因为我们目前大多数垃圾收集算法使用的就是分代收集算法,上面这样图呢是我在《JVM堆内存模型概括》中讲解到的图,大家可以先简单看一下,这里的分代垃圾收集算法把之前的垃圾收集算法的优点集于一身,首先将内存分为年轻代和老年代,而年轻代使用的是复制算法,而老年代使用的是标记清除或标记整理算法,因为年轻代是新生成的对象,大多数都是朝生夕逝的,所以不需要用很大的内存,就可以用复制算法来提高垃圾回收效率,而老年代都是存活比较稳定的对象,所以对内存空间要求比较高,所以可以使用标记清除或标记整理算法。

垃圾收集器

由于目前大多数使用的垃圾收集算法都是分代收集算法,所以现在的堆内存都分为新生代和老年代,而垃圾收集器也分用于新生代或者老年代的垃圾收集器,因为新生代与老年代的算法不同,所以垃圾收集器也不能混用。

垃圾收集器1——Serial收集器(用于新生代)

Serial收集器用于新生代,是比较早的垃圾收集器,是单线程进行收集的,使用复制算法。

垃圾收集器2——Serial Old收集器(老年代)

Serial Old是Serial收集器的老年代版本收集器,与Serial收集器配套使用,它也是单线程进行垃圾收集,使用的是标记整理算法。

垃圾收集器3——ParNew收集器(新生代)

ParNew收集器相比较于Serial收集器的不同是该收集器是多线程进行收集的。

垃圾收集器4——Parallel Scavenge收集器(新生代)

Parallel Scavenge收集器与ParNew收集器类似,都是多线程进行收集,都是使用的复制算法,但是其它收集器都是注重清理的效率,就是每次进行垃圾清理的时候不管使用多长时间都要清理最多的垃圾,但是我们知道垃圾清理的时候是会发生STW(在《java垃圾回收机制概括》一文中有详细讲解STW),所以清理的越干净所需要的时间越长,但是用户在使用的时候等待时间过长会产生不好的体验,而Parallel Scavenge收集器更注重用户体验,他可以设置用户最多等待时长,假如设置了用户最多等待时长为2秒,当垃圾收集使用时间到达2秒而还有假如一半垃圾没有收集的时候,收集器会暂停垃圾收集,继续让用户访问程序,剩下一半没有收集的垃圾会在下一次垃圾收集的时候再进行收集。

垃圾收集器5——Parallel Old收集器(老年代)

该收集器是Parallel Scavenge的老年代版本,也是使用的多线程收集以及标记整理算法,而且也注重用户体验。

垃圾收集器6——CMS收集器(Concurrent Mark Sweep)

通过该收集器的名称我们不难理解该收集器使用的算法是并行标记扫描,该收集器执行过程分为五个阶段,分别为1、初始标记;2、并发标记;3、重新标记;4、并发清理;5、并发重置;在这里大家大概了解一下,在以后的文章我会详细讲解这五个步骤的做了些什么,以及并发标记过程出现多标和漏标的情况怎样用“三色标记”算法解决。

垃圾收集器7——G1收集器(Garbage First)

通过该收集器的名称我们知道它是垃圾优先收集的意思,什么叫做垃圾优先呢,首先在这里我们要讲一下该垃圾收集器堆内存的分配与其他垃圾收集器不同,其他垃圾收集器将堆内存分为,新生代与老年代,每次收集的时候都是将全部的新生代或老年代进行收集,而G1垃圾收集器是将堆内存分为很多个固定大小的独立区域(Region),如下图

垃圾收集器以及垃圾收集算法_面试_09

这样我们就将对象存到这些小区域中,但是这些小区域是固定的,而我们的对象有大有小,假如区域1容纳了一个占60%空间的对象,而后面有来了一个占空间50%的对象,而区域1只能再容纳一个占空间40%的对象,所以50%的对象放到了区域2,这个时候又来了一个占100%的对象,它只能放到了区域三,这个是有三个区域分别有占比60%、50%、100%的对象,这个时候要进行垃圾收集了,假如三个区域的对象全部成为了垃圾对象,但是我们为了给用户良好的体验我们只有清理一个Region区域的对象,那么我们应该清理哪一个呢?答案肯定是区域3的100%对象,因为清理了这个对象可以最大的空出我们的整体内存空间来,这个就是G1先对要清理的垃圾进行了一个排序,优先清理对整体效果最好的垃圾。

垃圾收集器——ZGC收集器

该收集器是还在实验阶段,主要特点是:可以回收很大的内存(最大4T),停顿时间不超过10ms。该收集器的运作阶段为并发标记、并发预备重分配、并发重分配、并发重映射。该收集器的并发标记是标记在指针上的,在以后的文章我会详细讲解标记阶段所涉及到的“颜色指针”,这里由于时间关系就先讲这么多吧。

总结

目前垃圾收集器一直在更新迭代,因为没有一款垃圾收集器能堪称最完美,最高效的垃圾收集器,我们只有不断的研究,不断地通过复杂的算法计算才能不断的提高垃圾收集器的效率,因为最高效的垃圾收集器它底层的算法最复杂,希望小伙伴们可以好好学习,将来有机会可以创造出更好的垃圾收集器。文章创作不易,今天凌晨北京刮风下雨,三点半就被惊醒,四点半开始创作,现在七点半要去上班了,接下来的文章会将今天没有详细讲到的地方补充上,希望大家可以多多关注、共同学习、加油!