垃圾收集器就是使用一种或者多种垃圾回收算法,在不一样的内存分配策略下,进行垃圾回收的程序。因为内存分配策略不一样的缘由,因此垃圾回收算法以及垃圾收集器的种类也不尽相同,下图是JDK1.7 Update 14以后的HotSpot虚拟机所包含的全部的垃圾收集器。java
HotSpot中的收集器分类算法
图上整体分为两大类,年轻代(Young generation)和老年代(Tenured generation)。上图中的连线表示在年轻代和老年代之间,哪些收集器能够两两配合使用,“八字不合”的收集器是不能在一块儿的!注意到,G1收集器是当前最前沿的收集器,它不须要和其余收集器配合,本身就能完成年轻代和老年代的垃圾回收工做。多线程
1.Serial收集器并发
Serial收集器应该算是收集器家族中元老级的任务,它是一款历史比较悠久的收集器,在JDK1.3以前仍是新生代收集器的惟一选择。Serial的中文意思是“串行”,也就是说他是一个单线程工做的垃圾收集器,其全部的工做都是在单个线程单个CPU的状况下完成的。除了单线程以外,Serial收集器在进行垃圾回收的过程当中,须要暂停其余全部的用户线程,JAVA专家称这种状况为:“Stop The World”。这种好比真的是再形象不过了,由于在那一刻真的好像世界都中止了。有人举过一个形象的例子,你女友在给你打扫放假的时候,确定不会让你再处处乱跑,若是她一边打扫,你一边乱跑,极可能晚上就要睡沙发了。实际上,“Stop The world”致使的停顿现象,即使是如今的最新的G1垃圾收集器也不可能说彻底避免,而只能不断地缩短Stop The World的时间。布局
经过上面的介绍,你们可能以为Serial收集器多是一个又老又慢过期的收集器,估计已经被淘汰了。然而事实上并不是如此,它到目前为止依赖是虚拟机运行在client模式下的默认年轻代收集器。咱们先来看一下Serial收集器的工做的过程,以后能够和后面的几个收集器在进行对比,就能发现Serial收集器在某些特殊的环境下,仍是有优势的:性能
Serial/Serial Old收集器回收过程优化
正式由于Serial的单线程,因此它相比于其余的收集器来讲,优势就是简单而高效,对于单个CPU的环境的来讲,Serial收集器没有线程交互,因此回收的效率相对来讲就比较高。因此Serial收集器更适合运行在client模式下的虚拟机,如桌面应用等。ui
关于JVM Client模式和Server模式:Client模式采用的是轻量级的虚拟机,全部启动的比较快;Server模式采用的是重量级的虚拟机,因此启动比较慢。重量级的虚拟机在运行期间作了不少的优化,因此启动以后程序运行比较快。Client模式通常内存占用的状况比较小,VM在client模式默认-Xms是1M,-Xmx是64M;JVM在Server模式默认-Xms是128M,-Xmx是1024M;因此Client在进行Stop The World的时间相对来讲不会太长,因此使用简单快速的Serial收集器来进行垃圾回收时再合适不过的了。线程
2.ParNew收集器设计
ParNew名字前面的Paral其实是单词“parallel”的缩写,意思是并行。因此从名字就能够知道ParNew收集器应该是多线程,事实上它就是Serial收集器的多线程的版本,因此,它除了是多线程的以外,其余的全部的东西像控制参数、收集算法、Stop The World、对象分配规则、回收策略等都与Serial收集器彻底同样。ParalNew收集器回收过程以下图所示:
ParNew / Seria Old收集器回收过程
ParNew收集器相对于Serial收集器除了多线程以外,并无其余的特色。因此若是在单CPU的状况下,ParalNew收集器并不会比Serial的性能好,甚至由于存在线程的交互的开销,ParalNew性能反而更差。另外就是,在JDK1.5时期推出了CMS(Concurrent Mark Sweep),这个几乎被认为有划时代意义的垃圾收集真正实现了垃圾回收的并发操做,也就是用户线程和GC线程是同时工做的。可是你们从开头的分类图上能够看出,在新生代中,能够和CMS同时工做的只有Serial和ParNew能够与之搭配工做。因此,在多核的环境下,ParNew收集器是最佳的选择。
3.Parallel Scavenge收集器
Parallel Scavenge收集器是一个新生代收集器,它也是使用了复制算法的收集器(前面介绍的两种收集器都是复制算法),并且又是并行的多线程收集器,看起来好像和ParNew收集器没什么不一样。哲学上常说,存在便是合理的,一件东西不会无缘无故的出现,Parallel Scavenge也是同样,那么它到底有什么神奇之处呢?
Parallel Scavenge收集器的特色是它的关注点和其余的收集器不同,CMS收集器的关注点是尽量是缩短垃圾回收时用户线程的停顿时间,而Parallel收集器的目标则是达到一个可控制的吞吐量。所谓吞吐量就是CPU用于运行用户代码的时间与CPU总消耗时间的比值:
停顿时间越短越适合与用户交互的程序,由于与用户交互的程序须要有良好的响应速度来提高用户的体验。也就是说,在一系列的用户操做中,用户并不但愿出现长久停顿的状况。就比如你正在看某种大片,过程当中每隔一段时间就停顿一下,你确定很不爽。假如这个停顿的时间就是垃圾回收致使的,因此你固然但愿这个停顿的时间越短越好。Parallel Scavenge就是用来将吞吐量控制在一个能够接受的范围内。Parallel Scavenge提供几个参数来精确控制吞吐量:
参数 |
参数描述 |
-XX:MaxGCPauseMillis |
该参数容许设置一个大于0的毫秒数,收集器将尽量地保证 内存花费的时间不超过该值 |
-XX:GCTimeRatio |
该参数容许设置一个0~100之间的整数,也就是垃圾收集时间占用比,至关于吞吐量的倒数 |
-XX:+UseAdaptiveSizePolicy |
该参数是一个开关参数,打开以后就不须要制定新生代的大小(-Xmm),Eden与Suirvive的比例(-XX:SurvivorRatio)、晋升老年代对象大小(-XX:PreTenureSizeThreshold)等细节参数了,虚拟机会根据系统运行状况,动态调整这些参数 |
注意:虽然Paralle Scavenge的参数是能够精确控制程序运行的吞吐量的,可是并非GC停顿时间控制越小越好。由于GC停顿时间变短,是以牺牲GC吞吐量和新生代空间来换取的。也就是说,太小的GC停顿时间会致使更频繁地发生GC。因此,Paralle Scavenge参数要设置在一个合理的范围内,才能让系统更好的运行。若是对于这方面没有经验的人,可使用参数3,让系统本身决定吞吐量。
4.Serial Old收集器
Serial Old收集器相至关于Serial收集器的老年代版本,使用的是标记-整理的算法,一样他是一个单线程的收集器。如今这个收集器的主要做用就是在Client模式下,做为虚拟机老年代的回收的垃圾收集器使用。可是若是你要把用在Server模式中,他就具有下面两种用途:
Serial Old收集器的工做过程以下图所示:
ParNew / Seria Old收集器回收过程
5.Parallel Old收集器
Parallel Old是Parallel Scavenge收集器的老年代版本,使用的是多线程和标记-整理。这个算法是在JDK1.6以后才提供的,因此Serial Old才能够做为Parallel Scavenge收集器Jdk1.5以前的年轻代收集器配合使用。因此在JDK1.6出现以前,Parallel Scavenge收集器是比较尴尬的,一方面本身在年轻代中使用的是多线程的,而在老年代中,只有单线程的Serial Old能够选择。因此在Parallel Old收集器出现以前,Parallel Scavenge收集器的地位是十分尴尬的。因为在老年代中Serial Old的效率拖后腿,因此Parallel Scavenge收集器一直处于一种不给力的状态。
直到Parallel Old收集器出现以后,“吞吐量优先”才有了比较名副其实的应用组合,因此JDk1.6以后,在注重吞吐量以及CPU资源敏感的场景中,均可以优先考虑Parallel Scavenge加Parallel Old的组合。他们组合的垃圾回收过程以下图所示:
Parallel Scavenge / Parallel Old收集器回收过程
5.CMS收集器(Concurrent Mark Sweep)
CMS收集器的目标是以得到最短回收停顿时间为目标的收集器(注意和Parallel Old收集器加以区分,Parallel Old是目标是精确控制程序运行的吞吐量,即停顿时间可控制)。从名称上咱们能够看出来CMS使用的标记-清除的算法,它的运行过程相对来讲比较复杂,整个过程能够分为4个步骤:
咱们能够先来看一下CMS收集器的垃圾回收过程,以下图所示:
CMS垃圾回收过程
从图上能够看出,在初始标记和从新标记这两个阶段仍然须要"Stop The World"。初始标记只是标记一下GC Roots能直接关联到的对象,速度很快。并发标记的阶段就是进行GC Roots Tracing的过程,而从新标记的过程就是为了修正并发标记期间由于用户程序仍然运行而致使变更的那一部分对象的标记记录。这个过程当中的时间要比初始标记长一些,可是要远比并发标记的时间要短。因此CMS把标记阶段能够大体理解为两个阶段,一个阶段是能够并发标记的阶段,不会影响程序运行;另外一个阶段就是不能够并发标记的阶段,就是标记过程会影响程序运行,因此这个阶段要“Stop The World”。可是由于大部分标记工做已经在第一个阶段完成,因此第二部分的时间就很是短。相比于以前的收集器不加以区分的方式,这种方式能够大大减小由于标记而致使“Stop The World”停顿的时间。
从设计来讲,CMS使用的也是多线程的方式来进行垃圾回收,因为是和用户线程同时进行,且使用的标记-清除算法,因此它就存在如下三个明显的缺点:
5.G1收集器(Garbage First)
G1是一款面向服务端应用的垃圾收集器,HotSpot团队的目标是,在将来能够用G1替换掉JDK1.5中发布的CMS收集器。与其余的收集器相比,G1收集器具备以下特色:
在G1以前的其余收集器进行瘦的范围都是整个新生代和老年代,G1收集器java堆的内存布局与其余收集器有很大的差异,他将整个java堆分为多个大小相等的独立区域(Region),虽然还保留有新生代和老年代的概念,但新生代和老年代再也不是物理隔离的了,他们都是一部分Region(不须要连续)的集合。
G1的详解讲解会做为新的一章来分析,以上关于G1的描述摘抄子(深刻了解虚拟机),后面会有单独的一章来说G1收集器。