若是说收集算法是内存回收的方法论,那么垃圾收集器就是内存回收的具体实现。java虚拟机规范中对垃圾收集器应该如何实现并无任何规定,所以不一样的厂商、不一样的版本的虚拟机所提供的垃圾收集器都有可能会有很大的区别,而且通常都会提供参数供用户根据本身的应用特色和要求组合出各个年代所使用的收集器。html
相关系列博客:java
上图中展现了不一样年龄代的收集器,其中Serial、ParNew和Parallel Scavenge收集器做用于新生代,CMS、Parallel Old 和 Serial Old做用于老年代,G1在新生代和老年代均可以使用。不一样的收集器之间若是有连线,则说明他们能够相互搭配使用。算法
并行:指的是多条垃圾收集线程一块儿公共,可是此时用户工做线程仍处于等待状态。多线程
并发:指的是用户线程和垃圾收集线程同时工做,也有多是交替执行,用户程序在继续执行,而垃圾收集程序运行与另外一个CPU上。并发
吞吐量:吞吐量就是CPU用于运行用户代码的时间与CPU总消耗时间的比值,即吞吐量 = 运行用户代码时间 /(运行用户代码时间 + 垃圾收集时间)。虚拟机总共运行了100分钟,其中垃圾收集花掉1分钟,那吞吐量就是99%。post
Serial收集器是一款串行执行的收集器,它是历史最悠久,也是最基本的收集器,采用复制算法实现的新生代收集器。在jdk1.3之前,Serial收集器是新生代惟一的选择。它是一个单线程执行的收集器,工做时只会知用一个cpu或线程区执行,更重要的是Serial在工做期间必须停掉全部的用户线程,直至垃圾收集完成,这一过程咱们称之为“stop the world”。这项工做是由虚拟机自动执行和自动完成的,用户在不知情的状况下停掉了全部的线程,这对于一个最求响应速度来讲简直是没法接受的。下图展现了Serial收集器在工做时的运行流程:性能
因为Serial收集器的工做模式是单线程的,天然就没有了多线程环境下线程切换带来的性能开销,因此该收集器在单线程环境下更加简单高效。网站
Parnew是Serial收集器的多线程版本,也是新生代收集器。ParNew收集器和Serial收集器除了多线程工做外几乎是相同的,包括全部控制参数、收集算法、stop the world,对象分配规则,回收策略等都是同样的。运行流程以下图:url
虽然与Serial收集器相比仅仅多了多线程特性外,没有其它的创新之处,可是它倒是许多Server模式下的虚拟机新生代收集器的首选,缘由在于目前为止只有Serial和ParNew两个新生代收集器可以与性能优异的CMS配合使用。关于CMS介绍将在下文展开描述。线程
Parallel Scavenge也是一款使用复制算法的新生代收集器。该收集器与其它收集器不一样的是,它关注的目标是达到一个可控制的吞吐量,而CMS等收集器的关注点则是尽量地减小用户线程地停顿时间,提升用户体验。Parallel Scavenge收集器提供了两个参数用于精确控制吞吐量,分别是控制最大垃圾收集停顿时间的-XX:MaxGCPauseMillis参数以及直接设置吞吐量大小的-XX:GCTimeRatio参数。也所以,Parallel Scavenge 被成为“吞吐量优先”收集器。
停顿时间越短就越适合与用户交互较多地程序,这样用户体验才更好。而高吞吐量则可让出更多的cpu资源给用户线程,让程序更快的完成运算任务,更适合后台运算较多而不须要与用户交互的程序。
自适应调节策略是Parallel Scavenge收集器的特色,也是与ParNew收集器的区别。Parallel Scavenge经过打开-XX:+UseAdaptiveSizePolicy的设置,就不须要手动地调节新生代(-Xmn)大小,Eden和Survivor区的比例(-XX:SurvivorRatio)、晋升老年代对象年龄(-XX:PretenureSizeThreshold)等细节参数,而是根据当前系统运行状况来肯定这些参数,从而提升程序地吞吐量和缩短停顿时间,这一过程称之为GC自适应的调节策略(GC Ergonomics)。
另外值得注意的一点是,Parallel Scavenge没法已CMS配合使用,若是新生代选择了Parallel Scavenge收集器,那么老年代的收集器只能选用Serial Old或者Parallel Old来配置使用。
Serial Old是Serial收集器的老年代版本,也是单线程工做的,使用的是“标记-整理”算法。
该收集器主要用于Client模式下的虚拟机使用,若是在Server模式下能够与Parallel Scavenge收集器配合使用;做为CMS收集器的后备预案,在并发收集发生Concurrent Mode Failure时使用。运行流程以下:
Parallel Old是Parallel Scavenge的老年代版本,也是一个并行收集器,使用“标记-整理”算法。该收集器在jdk1.6后对外提供使用,Parallel Scavenge 和 Parallel Old配合使用的话,更加适合应用于高吞吐量和cpu敏感资源的场合。下面是这两个收集器配合使用的运行流程:
CMS(Concurrent Mark Sweep)是一个并发收集器,使用了“标记-清除”算法来实现的。该收集器最求的更短的停顿时间,从而提高用户体验,所以也很是符合使用在网站、B/S系统的服务端的应用。
CMS收集器的工做流程大概能够分为如下4个步骤:
因为标记和清除阶段能够和用户线程一块儿工做,所以几乎能够把CMS收集器的工做是并发的:
CMS是一款优秀的收集器,它的主要优势是低停顿,并发收集,所以也被成为并发低停顿收集器(Concurrent Low Pause Collector)。
固然,CMS收集器也有必定的缺点,主要包括一下几点:
运行示意图以下:
G1(Garbage-First)是一款面向服务端应用的垃圾收集器,JDK 7 Update4 后开始进入商用。HotSpot开发团队赋予它的使命是将来能够替换掉JDK 1.5中发布的CMS收集器。以前提供的收集器都是仅做用于新生代或者是老年代,可是G1收集器能够做用于新生代和老年代,由于使用G1收集器是java heap的内存结构有很大的不一样,它将整个Java堆划分为多个大小相等的独立区域(Region),虽然还保留有新生代和老年代的概念,可是他们已经没有了物理上的隔阂了,它们都是region的一部分的集合。
G1(Garbage-First)收集器是当今收集器技术发展的最前沿成果之一,与其余收集器相比,G1收集器具备如下特征:
G1收集器之因此可以创建可预测的停顿时间模型,由于他可以有计划地避免在整个Java堆中进行全区域的垃圾收集。G1跟踪各个Region里面的垃圾堆积的价值大小(回收所得到的空间大小以及回收所须要的经验值),在后台维护一个优先表,每次根据容许的收集时间,优先回收价值最大的Region。这种使用Region划份内存空间以及有优先级的区域回收方式,保证了G1收集器在有限的时间内能够获取尽量高的收集效率。
在G1收集器中,Region之间的对象引用以及其余收集器中的新生代和老年代之间的对象引用,虚拟机都是使用Remembered Set来避免全堆扫描的。G1中每一个Region都有一个与之对应的Remembered Set,虚拟机发现程序在对Reference类型的数据进行写操做时,会产生一个Write Barrier暂时中断写操做,检查Reference引用的对象是否处于不一样的Region中,若是是,便经过CardTable把相关引用信息记录到被引用对象所属的Region中的Remembered Set之中。当进行内存回收时,在GC根节点的枚举范围中加入Remembered Set便可保证不对全堆扫描,也不会有遗漏。
若是不计算维护Remembered Set的操做,G1收集器的运做大体分为如下几个步骤:
执行流程以下图:
收集器 | 串行、并行or并发 | 新生代/老年代 | 算法 | 目标 | 适用场景 |
---|---|---|---|---|---|
Serial | 串行 | 新生代 | 复制算法 | 响应速度优先 | 单CPU环境下的Client模式 |
Serial Old | 串行 | 老年代 | 标记-整理 | 响应速度优先 | 单CPU环境下的Client模式、CMS的后备预案 |
ParNew | 并行 | 新生代 | 复制算法 | 响应速度优先 | 多CPU环境时在Server模式下与CMS配合 |
Parallel Scavenge | 并行 | 新生代 | 复制算法 | 吞吐量优先 | 在后台运算而不须要太多交互的任务 |
Parallel Old | 并行 | 老年代 | 标记-整理 | 吞吐量优先 | 在后台运算而不须要太多交互的任务 |
CMS | 并发 | 老年代 | 标记-清除 | 响应速度优先 | 集中在互联网站或B/S系统服务端上的Java应用 |
G1 | 并发 | both | 标记-整理+复制算法 | 响应速度优先 | 面向服务端应用,未来替换CMS |
参考资料: 《深刻理解Java虚拟机-JVM高级特性与最佳实践》 -周志明
喜欢我写的博客的同窗能够关注订阅号【Java解忧杂货铺】,里面不按期发布一些技术干活,也能够免费获取大量最新最流行的技术教学视频