1.Serial收集器
(年轻代收集器,可与CMS和Serial Old配合使用)
最基本、发展最悠久的收集器,这是一个单线程收集器。他只会使用一个cpu或是一条线程去完成垃圾收集工作。但是更重要的是它在进行垃圾收集时必须停止其他所有工作线程,直到它收集完成。stop the world在用户看不见的情况下把用户正常工作的线程全部停掉。虽然这是它的缺点但是对于限定单个cup的环境来说,Serial并没有线程交互开销,专心做垃圾收集自然可以获得单线程最高收集效率。
在用户应用场景中,分配给虚拟机管理的内存一般来说不会很大,收集几十兆甚至一两百兆的新生代,停顿时间完全可以控制在几十毫秒最多一百多毫秒以内,只要不是频繁发生,这点停顿是可以接受的。所以Serial收集器对于运行在Client模式下的虚拟机来说是一个很好的选择。
2.ParNew收集器
(年轻代收集器,可与CMS和Serial Old配合使用)
(可与CMS收集器配合使用是该收集器是许多运行在server模式下的虚拟机中首选的新生代收集器的重要原因。)
在实现方面,ParNew其实就是Serial的多线程版本。除了进行垃圾收集之外,其余行为包括Serial收集器可用的所有控制参数、收集算法、stop the world、对象分配规则等都和Serial一样。
ParNew在单个收集器下性能绝不会有Serial好,随着线程数量增加ParNew会慢慢好于Serial。
3.Parallel Scavenge收集器-吞吐量优先收集器
(可与Serial Old和Parallel Old配合使用,不能和CMS配合使用)
Parallel Scavenge也是一个并行的多线程收集器,但其特殊之处就在于其收集目标是达到一个可控制的吞吐量(吞吐量=运行用户代码时间/(允许用户代码时间+垃圾收集时间)虚拟机总共运行100分钟,其中垃圾收集花掉1分钟,那吞吐量就是99%)。
停顿时间越短就越适合需要与用户交互的程序,良好的响应速度能提升用户体验,而高吞吐量则可以高效地利用CPU时间,尽快完成程序的运算任务,主要适合在后台运算而不需要太多交互的任务。
MaxGCPauseMillis参数允许的值是一个大于0的毫秒数,收集器将尽可能的保证内存回收花费的时间不超过设定值。不过不是设置的越小速度越快,设置的太小会使吞吐量和新生代空间变小,导致GC过于频繁。
GCTimeRatio参数值应当是一个大于0小于100的整数,默认值为99。
4.Serial Old收集器
Serial Old是Serial收集器的老年代版本,其主要意义在于给Client模式下的虚拟机使用。
两大用途:一是在jkd1.5以及之前的版本中于Scavenge收集器搭配使用,另一种用途就是作为CMS收集器的后备预案。
5.Parallel Old收集器
该收集器出现后Parallel终于有了比较名副其实的吞吐量优先收集器的搭配使用。
6.CMS收集器
(可以和Serial和ParNew收集器配合使用)
它是一款以获取最短停顿为目标的收集器。目前很大一部分的Java应用集中在互联网站或者B/S系统的服务端上,这类应用尤其重视服务器响应速度,希望系统停顿时间最短,以给用户带来较好体验。
其运作过程包括四个步骤:
1.初始标记:stop the world之后,仅仅标记一下GC Roots能直接关联到的对象,速度很快。
2.并发标记:在初始标记的基础上进行可达性分析找出该回收的对象。
3.重新标记:修正并发标记期间因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录。该阶段耗时远比并发标记短。
4.并发清理:对“已死”对象进行清除。
缺点:
1.CMS收集器对CPU资源非常敏感。在并发阶段,它虽然不会导致应用程序停顿,但是会因为占用了一部分线程而导致应用程序变慢,总吞吐量降低。
2.CMS收集器无法清理浮动垃圾(在垃圾收集阶段,用户线程还在产生垃圾,而这些垃圾只能等到下次回收时才能清理,),那么就必须预留足够的空间。还可能导致出现“Concurrent Mode Failure”失败而导致另一次Full GC产生。
3.CMS是基于“标记-清除”算法实现的收集器,这意味着收集结束时会有大量空间碎片产生。碎片空间过多时,将会给大对象分配带来很大麻烦,往往会出现老年代还有很大空间剩余,但无法找到连续空间来分配当前对象,不得不提前出发一次full GC。
虽然CMS提供了UseCMSCompactAtFullCollection开关参数(默认就是启动的)能在CMS顶不住要进行Full GC时开启内存碎片的合并整理过程,但会因此使得停顿时间变长。
网友评论