垃圾收集器关系图:
如果两个收集器之间存在连线,就说明它们可以搭配使用。它们说在的区域则表示这个收集器属于新生代收集器还是老年代收集器。其中Serial(串行)、Parallel(并行)
1、Serial收集器
Serial收集器是最基础、历史最悠久的收集器,是HotSpot虚拟机新生代收集器的唯一选择。这个收集器是一个单线程工作的收集器。这个收集器再进行垃圾收集时,必须停掉所有的工作线程,直到收集完成。这个停掉的工作是后台自己执行的,用户并不知情。这个是我们无法接受的。
从上面的种种缺点看去似乎这个收集器已经被时代抛弃,没有优点。但是它依旧是HotSpot虚拟机运行再客户端模式下默认的新生代收集器。因为它有一个很大的优点简单而高效。再内存环境受限的环境,它是所有收集器里面的额外内存消耗最小的。一般来说分配给虚拟机管理的内存一般不会特别大,对于几十兆甚至一两百兆的新生代,Serial垃圾收集器的停顿时间完全可以控制再可接受范围。所以, Serial收集器对于运行在客户端模式下的虚拟机来说是一个很好的选择。
2、ParNew收集器
ParNew收集器实质上是Serial收集器的多线程并行版本,出来可以同时多条线程进行垃圾收集外,其余行为几乎与Serial收集器一致。
这个收集器明明没有太大的创新为什么能有怎么重要的地位呢,那就是因为它的搭档CMS收集器。CMS第一款真正意义上支持并发的垃圾收集器,它首次 实现了让垃圾收集线程与用户线程同时工作。但这个收集器只能Serial和ParNew这两个新生代收集器配合使用。这样奠定了ParNew的地位。随着G1收集器的产生,这一组合被逐渐取代,官方希望它能完全被G1所取代,ParNew和CMS从此只能互相搭配使用,再也没有其他收集器能够和它们配合了。也可以理解为从此以后,ParNew合并入CMS,成为它专门处理新生代的组成部分。ParNew可以说是HotSpot虚拟机中第一款退出历史舞台的垃圾收集器。
3、Parallel Scavenge收集器
Parallel Scavenge收集器是一款新生代收集器,它基于标记复制算法实现。也是能够并行收集的多线程收集器。它独特的点在于它的注重点与其他收集器不同,CMS等收集器的关注点是尽可能的缩短垃圾收集时用户线程的停顿时间,而Parallel Scavenge的注重点是一个可控的吞吐量。
注重停顿时间的垃圾收集器适合注重用户良好体验的程序,而高吞吐量则是更高效的利用资源,尽快完成程序的运算任务,适合在后台不需要过多交互的程序。
这个收集器提供了两个参数用于精确控制吞吐量,分别是控制最大垃圾收集停顿时间 的-XX:MaxGCPauseMillis参数以及直接设置吞吐量大小的-XX:GCTimeRatio参数。 -XX:
4、Serial Old收集器
Serial Old是Serial收集器的老年版本,它是一个单线程收集器,使用标记整理算法。这个收集器的主要作用是再客户端模式下的HotSpot虚拟机使用。再服务端下一种是JDK5即以前与ParallelScavenge收集器搭配使用,另一种就是作为CMS收集器发生失败时的后背预案。
5、Parallel Old收集器
parallel Old是parallel Scavenge收集器的老年版本,支持多线程并发收集,基于标记整理算法实现。出现在JDK6后。当注重吞吐量或者处理器资源稀缺的时候,都会优先考虑 parallel Scavenge+Parallel Old收集器这个组合。
6、CMS收集器 (并发收集、低停顿)
CMS(Concurrent Mark Sweep)收集器是以获取最短回收停顿时间的为目标的收集器。注重服务的响应速度,希望系统停顿时间尽可能短,以给用户更好的交互体验。这个收集器是基于标记清除算法实现的。用于老年代的收集。
收集过程有四个阶段:1、初始标记 2、并发标记 3、重新标记 4、并发清除
四个阶段中初始标记和重新标记仍需要暂停所有的用户线程(Stop The World),但为什么说这个收集器也暂停了所有的线程,为什么还能做到停顿时间短呢。因为初始标记阶段只是标记GC Roots能直接关联的对象,这个过程很快。而并发标记时才进行沿GC Roots遍历所有对象,这个工作量说不小的,但这个过程并没有停顿用户线程,而是与其并发执行,如果再过程出现对象引用关系改变,则使用增量更新的方法将其标记。待重新标记阶段就是为了解决这个并发过程中因为改变而被标记的对象。这个阶段是要暂停用户线程的,但这部分的工作量也不大。最后全部标记玩就进入了并发清除的阶段了。这部分也是与用户线程并发进行的。
从整体上看来耗时长的并发标记和并发清除都没有暂停用户线程,所有可以说:从总体上来说,CMS收集器的内存回收过程是与用户线程一起并发执行的。
缺点:
- CMS收集器对CPU资源很敏感。它虽然不会导致用户线程停顿,但也会因为占用一部分线程导致应用程序变慢。它默认启动的回收线程数是(核心线程数+3)/4,所以随着核心线程数的降低,CMS收集器的弊端会越来越明显。
- CMS是一款基于“标记-清除”算法实现的收集器,这意味着收集结束时会有大量空间碎片产生。空间 碎片过多时,将会给大对象分配带来很大麻烦,往往会出现老年代还有很多剩余空间,但就是无法找 到足够大的连续空间来分配当前对象,所以会提前导致Full GC的到来。
- CMS无法处理浮动垃圾(再清除阶段用户线程还在运行,产生的垃圾)。必须等到下次GC时才能清理,而且不能等到老年代满了后再清理,因为再清理过程中用户线程还在产生对象,所以要预留一定内存,提前开启垃圾清理。
7、G1收集器(Garbage First)
G1是一种“停顿时间模型”的收集器,它能指定时间N,确保消耗再垃圾收集上时间大概率不超过N毫秒的目的。G1收集器一改之前的分区收集思想,开创了面对局部收集的设计思路。它将java堆划分为多个大小相等的独立区域Region。它可以面对堆内存任何部分组成回收集进行回收。这个模型回收哪块的衡量标准是哪块Region垃圾最多,再N毫秒内回收收益最大。这就是G1收集器的Mixed GC模式。
再并发操作阶段,CMS收集器采用增量更新算法实现,而G1 收集器则是通过原始快照(SATB)算法来实现的。
收集过程:
- 初始标记:仅仅只是标记一下GC Roots能直接关联到的对象,需要暂停用户线程,但耗时很短。
- 并发标记:从GC Root开始对堆中对象进行可达性分析,递归扫描整个堆 里的对象图,找出要回收的对象,这阶段耗时较长,但可与用户程序并发执行。当对象图扫描完成以 后,还要重新处理SATB记录下的在并发时有引用变动的对象。 ·
- 最终标记:对用户线程做另一个短暂的暂停,用于处理并发阶段结束后仍遗留 下来的最后那少量的SATB记录。 ·
- 筛选回收:负责更新Region的统计数据,对各个Region的回 收价值和成本进行排序,根据用户所期望的停顿时间来制定回收计划,可以自由选择任意多个Region 构成回收集,然后把决定回收的那一部分Region的存活对象复制到空的Region中,再清理掉整个旧 Region的全部空间。这里的操作涉及存活对象的移动,是必须暂停用户线程,由多条收集器线程并行 完成的。
毫无疑问,可以由用户指定期望的停顿时间是G1收集器很强大的一个功能,设置不同的期望停顿 时间,可使得G1在不同应用场景中取得关注吞吐量和关注延迟之间的最佳平衡。当然这个值也得是一个可能的值,要是太低了,就会导致每次回收不了多少,回收次数增加。