JVM系列之垃圾收集器

   Java虚拟机规范中对垃圾收集器应该如何实现并没有任何规定,因此不同的厂商、不同版本的虚拟机所提供的垃圾收集器都可能会有很大差别,并且一般都会提供参数供用户根据自己的应用特点和要求组合出各个年代所使用的收集器。



图中展示了7种作用于不同分代的收集器,如果两个收集器之间存在连线,就说明它们可以搭配使用。虚拟机所处的区域,则表示它是属于新生代收集器还是老年代收集器。

一、概念理解

   1. 并发和并行

     
  • 并行(Parallel):指多条垃圾收集线程并行工作,但此时用户线程仍然处于等待状态。
  •   
  • 并发(Concurrent):指用户线程与垃圾收集线程同时执行(但不一定是并行的,可能会交替执行),用户程序在继续运行,而垃圾收集程序运行于另一个CPU上。
  •  

  2. Minor GC 和 Full GC

      
  • Minor GC:指发生在新生代的垃圾收集动作,因为Java对象大多都具备朝生夕灭的特性,所以Minor GC非常频繁,一般回收速度也比较快。
  •   
  • Full GC:指发生在老年代的GC,出现了Major GC,经常会伴随至少一次的Minor GC(但非绝对的,在Parallel Scavenge收集器的收集策略里就有直接进行Major GC的策略选择过程)。Major GC的速度一般会比Minor GC慢10倍以上。
  •  

  3. 吞吐量
     吞吐量就是CPU用于运行用户代码的时间与CPU总消耗时间的比值,即吞吐量 = 运行用户代码时间 /(运行用户代码时间 + 垃圾收集时间)。
虚拟机总共运行了100分钟,其中垃圾收集花掉1分钟,那吞吐量就是99%。

  4. client模式 和 server模式

      
  • client模式:应用于桌面应用程序。-client 参数指定启动java程序。优点:启动速度快。
  •   
  • server:应用于服务端应用程序。-server 参数指定启动java程序。特点:启动慢,运行快。
  •  

二、串行分类器(Serial)



 

  1. 特性:这个收集器是一个单线程的收集器,但它的“单线程”的意义并不仅仅说明它只会使用一个CPU或一条收集线程去完成垃圾收集工作,更重要的是在它进行垃圾收集时,必须暂停其他所有的工作线程,直到它收集结束。Stop The World
  2. 应用场景:Serial收集器是虚拟机运行在Client模式下的默认新生代收集器,最适用于应用程序的内存使用少于100MB的场景(少于100MB,并行和并发收集器起不了太大的性能提升)。
  3. 优势:简单而高效(与其他收集器的单线程比),对于限定单个CPU的环境来说,Serial收集器由于没有线程交互的开销,专心做垃圾收集自然可以获得最高的单线程收集效率。

 


三、并行分类器(Parallel/Throughput

  Parallel Scavenge收集器 ,ParNew收集器,Parallel Old收集器



 

  1. 特性:Throughput收集器使用多线程回收新生代空间和老年代空间,GC速度比Serial收集器快得多,Throughput收集器在Minor GC 和 Full GC时会暂停所有应用线程 ,直到它收集结束。Stop The World
  2. 应用场景:Throughput收集器是Server级虚拟机(多CPU的Unix机器以及任何64位虚拟机)的默认收集器,停顿时间越短就越适合需要与用户交互的程序,良好的响应速度能提升用户体验,而高吞吐量则可以高效率地利用CPU时间,尽快完成程序的运算任务,主要适合在后台运算而不需要太多交互的任务。
  3. 优势:使用Throughput收集器处理应用程序线程的批量任务能最大程度的利用CPU的处理能力,通常能获得更好的性能。

 

 

四、CMS收集器

  


 

  1. 特性:Cms收集器是一种以获取最短回收停顿时间为目标的收集器。
  2. 应用场景:目前很大一部分的Java应用集中在互联网站或者B/S系统的服务端上,这类应用尤其重视服务的响应速度,希望系统停顿时间最短,以给用户带来较好的体验。CMS收集器就非常符合这类应用的需求。
  3. 优势:并发收集、低停顿。应用程序只在Minor GC以及后台线程扫描老年代时发生极其短暂的停顿。
  4. 缺点:
  • CMS收集器对CPU资源非常敏感

       其实,面向并发设计的程序都对CPU资源比较敏感。在并发阶段,它虽然不会导致用户线程停顿,但是会因为占用了一部分线程(或者说CPU资源)而导致应用程序变慢,总吞吐量会降低。
       CMS默认启动的回收线程数是(CPU数量+3)/ 4,也就是当CPU在4个以上时,并发回收时垃圾收集线 程不少于25%的CPU资源,并且随着CPU数量的增加而下降。但是当CPU不足4个(譬如2个)时,CMS对用户程序的影响就可能变得很大。

       如果CMS的后台垃圾收集线程无法获得完成他们任务所需的CPU资源,或者如果堆变得过度碎片化以至于无法找到连续空间分配对象,CMS就蜕变到Serial收集器的行为:暂停所有应用线程,使用单线程回收,整理老年代空间。

 
  • CMS收集器无法处理浮动垃圾

      

CMS收集器无法处理浮动垃圾,可能出现“Concurrent Mode Failure”失败而导致另一次Full GC的产生。

由于CMS并发清理阶段用户线程还在运行着,伴随程序运行自然就还会有新的垃圾不断产生,这一部分垃圾出现在标记过程之后,CMS无法在当次收集中处理掉它们,只好留待下一次GC时再清理掉。这一部分垃圾就称为“浮动垃圾”。
      也是由于在垃圾收集阶段用户线程还需要运行,那也就还需要预留有足够的内存空间给用户线程使用,因此CMS收集器不能像其他收集器那样等到老年代几乎完全被填满了再进行收集,需要预留一部分空间提供并发收集时的程序运作使用。要是CMS运行期间预留的内存无法满足程序需要,就会出现一次“Concurrent Mode Failure”失败,这时虚拟机将启动后备预案:临时启用Serial Old收集器来重新进行老年代的垃圾收集,这样停顿时间就很长了。

  • CMS收集器会产生大量空间碎片

     CMS是一款基于“标记—清除”算法实现的收集器,这意味着收集结束时会有大量空间碎片产生。空间碎片过多时,将会给大对象分配带来很大麻烦,往往会出现老年代还有很大空间剩余,但是无法找到足够大的连续空间来分配当前对象,不得不提前触发一次Full GC。

五、G1收集器



 

  1. 特性:G1收集器也是一种并发收集器。设计初衷是为了尽量缩短处理超大堆(大于4GB)时产生的停顿。使用G1收集器时,Java堆的内存布局就与其他收集器有很大差别,它将整个Java堆划分为多个大小相等的独立区域(Region),虽然还保留有新生代和老年代的概念,但新生代和老年代不再是物理隔离的了,它们都是一部分Region(不需要连续)的集合。
  2. 应用场景:目前很大一部分的Java应用集中在互联网站或者B/S系统的服务端上,这类应用尤其重视服务的响应速度,希望系统停顿时间最短,以给用户带来较好的体验。CMS收集器就非常符合这类应用的需求。
  3. 优势:G1从整体来看是基于“标记—整理”算法实现的收集器。G1的设计理念使得它比CMS更不容易遭遇Full GC。

六、总结

  Serial收集器:最适用于应用程序的内存使用少于100MB的场景。

  Throughput收集器:如果平均响应时间比最大响应时间更重要(譬如90%的响应时间),采用Throghput收集器通常就能满足。如果目标是要尽可能的缩短响应时间,那么选择使用Concurrent收集器更合适。Concurrent收集器的前提条件是CPU足够强劲

  Concurrent收集器:一般情况下,堆空间小于4GB时,CMS收集器的性能比G1收集器好。使用大型堆或者巨型堆时,由于G1收集器可以分割工作,通常它比CMS收集器表现更好。

猜你喜欢

转载自ncs123.iteye.com/blog/2387734