JVM垃圾收集器种类及特点

    垃圾收集器是内存回收的具体实现。Java虚拟机规范中对垃圾收集器如何实现没有明确的规定,因此不同的厂商、不同版本的虚拟机所提供的垃圾收集器都可能存在很大差别,并且一般都会提供参数供用户自己根据自己的应用特点和要求组合出各个年代所使用的垃圾收集器。目前在JDK1.7 Update14以后的hotspot虚拟机,都包含了如下的垃圾收集器:

上图展示了7中作用于不同分代的收集器,如果两个收集器之间存在连线,就说明他们可以搭配使用。虚拟机所处的区域,则表示它是属于新生代收集器还是老年代收集器。
    首先明确一个观点:虽然我们是在对各个收集器进行比较,但是并非为了挑选出一个最好的收集器。因为到目前为止还没有最好的收集器出现,更没有万能的收集器,所以开发者只能选择针对具体应用最合适的收集器。

    1、Serial收集器
       Serial收集器是最基本、发展历史最悠久的收集器,在JDK1.3.1之前是新生代搜集的唯一选择。Serial的运行过程如下图:
      
       优点:简单高效、对于限定单个cpu的环境来说,serial收集器没有线程交互的开销,可专心做垃圾收集以获得最高的单线程收集效率。
       缺点:单线程收集器,在进行垃圾收集时,必须暂停其他所有的工作线程,直到它搜集结束。
       适用场景:用户桌面应用(一般用户的桌面应用场景中,分配给虚拟机管理的内存一般来说不会很大,收集几十兆或者一两百兆的新生代),停顿时间可以控制在100毫秒左右,这点停顿是可以接受的。
    2、ParNew收集器
       ParNew收集器其实是Serial收集器的多线程版本。除了多线程收集,其他与Serial收集器相比并没有太多创新之处,但它却是许多运行在Server模式下的虚拟机中首选的收集器,其中的一个与性能无关的原因是,除了Serial收集器,目前只有它能和CMS收集器配合工作(CMS收集器是hotspot虚拟机中第一款真正意义上的并发收集器,简单来说就是你可以一边制造垃圾,收集器在不打断你的情况下进行收集)。
       ParNew收集器适用于多核cpu环境,在单核情况下性能往往不如Serial收集器,甚至优于存在线程交互的开销,该收集器在通过超线程技术实现的两个cpu的环境中都不能百分之百的保证可以超越Serial收集器。不过一般在服务器环境下,多核心处理器非常常见,开发者可以使用-XX:ParallelGCThreads参数来限制垃圾收集的线程数。
       ParNew垃圾收集器的工作流程如下:
      
   3、Parallel Scavenge收集器
     与其收集器关注点不同的是,Parallel Scavenge收集器的目标则是达到一个可控制的吞吐量(Throughput),吞吐量=运行用户代码时间/(运行用户代码时间+垃圾收集时间)。
     适用场景:后台运算而不需要太多交互的任务。
     特点:Parallel Scavenge收集器有一个参数-XX:+UseAdaptiveSizePolicy值得关注,这是一个开关参数,当这个参数打开之后,就不需要手工指定新生代的大小(-Xmn),eden和Surivior区的比例(-XX:SurvivorRatio)、晋升老年代对象年龄(-XX:pretenureSizeThreshold)等细节参数了,虚拟机会根据当前系统的运行情况收集性能监控信息,动态调整这些参数以提供最合适的停顿时间或者最大的吞吐量,这种调节方式称为GC自适应的调节策略。
   4、Serial Old收集器
     Serial Old是Serial收集器的老年代版本,它同样是一个单线程收集器,使用标记整理算法。
     使用场景:
       1)Client模式。
       2)Server端,JDK1.5以及以前的版本中与Parallel Scavenge收集器搭配使用。
       3)Server端,CMS收集器的后备预案,在并发收集发生Concurrent Mode Failure时使用。
      运行示意图如下:
   5、Parallel Old收集器
      这个收集器是JDK1.6中开始提供的,在此之前跟Parallel Scavenge相对应的是老生代收集器是PS MarkSweep收集器,这个收集器本身与Serial Old非常接近,所以在官方的许多质量中都是直接以Serial Old代替PS MarkSweep进行讲解。
      由于Serial Old收集器是单线程,所以其在服务端应用性能会拖累Parallel Scavenge,也就是说是用了Parallel Scavenge也不一定获得吞吐量最大化的效果。
      直到Parallel Old收集器出现后,“吞吐量优先”收集器终于有了比较名副其实的应用组合,在注重吞吐量以及CPU资源敏感的场合,都可以优先考虑Parallel Scavenge+Parallel Old收集器组合,这两个组合工作过程如下:
     
   6、CMS收集器
      CMS(Concurrent Mark Sweep)收集器是一种以最短回收停顿时间为目标的收集器。目前很大一部分JAVA应用集中在互联网网站或者B/S系统的服务端上,这类应用尤其重视服务的响应速度,希望系统停顿时间最短,以给用户带来较好的用户体验,而CMS收集器就非常符合这类应用的需求。
      从名字(Mark Sweep)上就可看出,CMS收集器是基于“标记-清除”算法实现的,它的运作过程分为4个步骤,包括:初始标识、并发标识、重新标识、并发清除。其中初始标识和重新标识这两个步骤仍然需要“Stop the world”。初始标记仅仅只是标记一下GCRoots能直接关联到的对象,速度很快,并发标记阶段就是进行GC Roots Tracing的过程,而重新标记阶段则是为了修正并发标记期间因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录,这个阶段的停顿时间一般会比初始标记阶段稍长一些,但远比并发标记的时间短。
      由于整个过程中耗时最长的并发标记和并发清除过程收集器线程都可以与用户线程一起工作,所以从总体上来说,CMS收集器的内存回收过程是与用户线程一起并发执行的。如下图所示:

      优点:并发收集、低停顿。
      缺点:1、CPU资源敏感。
           2、无法处理浮动垃圾(Floating Garbage),即无法收集并发运行中产生的新的垃圾。
           3、容易产生空间碎片。不过为了解决这个问题,CMS收集器提供了一个+UserCmsCompactAtFullCollection开关参数(默认开启),用于在CMS收集器顶不住要进行FullGC时开启内存碎片的合并整理工作,这个过程是无法并发的,所以每隔一段时间就会出现停顿时间稍长的问题。此外,还有另外一个参数+XX:CMSFullGCsBeforeCompaction,这个参数是用于设置执行多少次不压缩的FullGC后,跟着来一次压缩的(默认值为0,即每次进入Full GC时都进行碎片整理)。、
     7、G1收集器(了解)
       G1(Garbage-First)是目前最前沿的成果之一。是面向服务端应用的垃圾收集器,hotspot团队赋予它的使命是在未来替换掉JDK1.5中发布的CMS收集器。在JDK7u4(即JDK Update4)及以后的版本中G1收集器可以进行商用了。
       优点:并行与并发、分代收集、空间整合、可预测的停顿

参考文献:《深入理解Java虚拟机:JVM高级特性与最佳实践(第二版)》 周志明著

猜你喜欢

转载自xiaoyun34286136.iteye.com/blog/2328305