概述
JVM垃圾收集器分类
新生代的垃圾收集器有Serial、ParNew、Parallel Scavenge以及G1;老年代的垃圾收集器有CMS、Serial Old、Parallel Old以及G1。如下图,如果两个收集器之间存在连线,就说明它们可以配合使用。
Serial收集器
serial收集器是一个单线程的收集器,使用”复制“算法,在进行GC操作(垃圾收集)时暂停其它所有工作线程,并且只使用一个cpu或者一个收集线程去完成垃圾收集工作。它是虚拟机运行在Client模式下的默认新生代收集器,与其他收集器的单线程相比,较为简单高效。
ParNew收集器
ParNew收集器是Serial收集器的多线程版本,二者共用了很多代码,只不过ParNew收集器可以使用多个cpu或者多个收集线程去完成垃圾收集工作。它是JVM运行时Server模式下的新生代收集器的首选(其中一个主要原因是除了Serial收集器之外,目前只有它能够与老年代的并发收集器CMS配合使用)。ParNew收集器在单个cpu的环境中不会有比Serial收集器更好的效果,由于存在线程交互的开销,该收集器在通过超线程技术实现的两个cpu的环境中都不能百分之百的保证可以超越Serial收集器。但是随着cpu的数量增加,它对于GC时系统资源的有效利用还是有好处的。
Parallel Scavenge收集器
Parallel Scavenge收集器也是使用"复制"算法的收集器,而且也是并行的多线程收集器,但是Parrallel Scavenge收集器是“吞吐量优先”收集器:它的关注点不是尽可能缩短垃圾收集时用户线程的停顿时间,而是尽可能达到一个可控制的吞吐量。
所谓吞吐量就是cpu用于运行用户代码工作代码的时间在cpu总运行时间的占比。
吞吐量 = 运行用户代码时间 /(运行用户代码时间+垃圾收集器时间)
进行垃圾收集的停顿时间越短越适合需要与用户进行交互的程序,良好的响应速度能够提升用户体验,而高吞吐量则可以高效的利用cpu时间,尽快的完成程序的运算任务,只要适合后台运算而不需要太多的交互任务。
同时,Parallel Scavenge收集器与ParNew收集器的其中一个重要区别就是自适应调节策略:Parallel Scavenge收集器在设置好基本内存数据(如最大堆-Xmx),然后设置最大停顿时间(MaxGCPauseMillis参数)或者吞吐量(GCTimeRatio)参数为虚拟机建立一个最优目标后,可以通过参数-XX:+UseAdaptiveSizePolicy打开自适应调节策略,虚拟机会根据当前系统的运行情况收集信息监控信息,动态调节新生代大小、Eden和Survivor区空间比例、晋升老年代对象大小等细节参数来提供最适合的停顿时间或者最大吞吐量。
Serial Old收集器
Serial Old收集器是Serial收集器的老年代版本,同样是一个单线程收集器,使用“标记-整理”算法,也是给Client模式下的虚拟机使用。在Server模式下有两种用途:
一、在JDK1.5之前的版本中与Parallel Scavenge收集器配合使用。
二、作为CMS收集器的后备方案,在并发收集发生Concurrent Mode Failure 时使用。
Parallel Old收集器
Parallel Old收集器是Parallel Scavenge收集器的老年代版本,使用多线程和“标记-整理”算法。在注重吞吐量以及cpu资源敏感的场合,可以优先考虑Parallel Scavenge加Parallel Old收集器。
CMS收集器
CMS收集器(Concurrent Mark Sweep)是一种以获取最短回收停顿时间为目标的收集器。是基于“标记-清除”算法来实现的,运行过程分为以下四步骤:
- 初始标记
停止Java所有执行线程,标记GC Roots能直接关联的对象,速度很快。
- 并发标记
进行GC RootsTracing的过程
- 重新标记
停止Java所有执行线程,为了修正并发标记期间因用户继续执行而导致标记发生变动的对象的标记记录,停顿时间稍长。
- 并发清除
整个过程中耗时最长的并发标记和并发清除收集器线程可以与用户线程一起工作,初始标记和重新标记所消耗的时间相比很少,因此CMS收集器的回收过程可以看作是与用户线程一起并发执行的。
CMS收集器的优点:并发收集、低停顿。
但是CMS收集器有以下三个明显的缺陷:
一、CMS收集器对cpu资源非常敏感。面向并发设计的程序都对cpu资源比较敏感。在并发执行的过程中,虽然不会导致用户线程的停顿,但是会因为占用了一部分cpu资源而导致应用程序变慢,总吞吐量下降。
二、CMS收集器无法处理浮动垃圾,可能出现”Concurrent Mode Failure“失败而导致另一次Full GC的发生。由于CMS并发清理阶段用户线程仍然在运行,自然会有新的垃圾不断产生,这部分垃圾由于没有被标记,只能在下一次GC时进行处理。这部分垃圾被称为”浮动垃圾“。也是由于CMS收集器线程与用户线程并发执行,需要为用户线程预留一部分内存空间来存放并发执行时用户线程产生的对象,因此使用CMS收集器需要指定当老年代空间使用了百分之多少后触发。要是CMS运行期间预留的内存不足时,就会出现一次“Concurrent Mode Failure”失败,这时虚拟机将启动后备预案:临时启动Serial Old收集器来重新对老年代的垃圾进行回收,导致较长的收集停顿。
三、CMS收集器是基于“标记-清除”算法实现的。因此,在收集结束后会产生大量的不连续的空间碎片。当空间碎片太多时,找不到足够的连续的空间来分配当前对象,便会触发一次Full GC。但是,CMS收集器提供了一个参数-XX:CMSFullGCsBeforeCompaction,这个参数用于设置在进行了多少次收集操作之后,将空间碎片进行一次压缩整理。
G1收集器
G1是一款面向服务器端应用的垃圾收集器,能够在整个新生代和老年代进行垃圾收集。使用G1收集器时,Java堆的内存被划分为多个大小相等的独立区域,新生代和老年代不再进行物理隔离,它们都是一部分独立区域的集合。
G1收集器的运作大致可以分为以下几步:
- 初始标记
标记一下GC Roots能直接关联到的对象,并且修改TAMS(Next Top at Mark Start)的值,让下个阶段用户程序并发执行时,能够在可用的独立区域创建新对象,需要停顿用户线程,耗时较短。
- 并发标记
从GC Roots开始对堆中对象进行可达性分析,找出存活的对象,耗时较长,能够与用户线程并发执行。
- 最终标记
将上个阶段用户线程继续运作而导致标记产生变化的那一部分标记进行记录,需要停顿用户线程。
- 筛选回收
首先对各个独立区域的回收价值和成本进行排序,根据用户所期望的GC停顿时间来指定回收计划。可以与用户线程并发执行,但是停顿用户线程的情况下,效率更高。
它设计的目的是为了替代CMS收集器。与其他GC收集器相比,具有以下特点:
一、并行和并发:在多个cpu、多核的硬件情况下,G1能够充分利用cpu来缩短收集停顿的时间。可以通过并发的方式让Java程序继续执行。
**二、分代收集:**分代概念在G1收集器中时依然保留的,虽然G1收集器可以单独使用来管理整个GC堆,但是它能够采用不同的方式处理新创建的对象和已经存活一段时间、经历过多次GC的旧对象以获取更好的收集效果。
三、空间整合:G1从整体上来看是基于“标记-整理”算法实现的收集器,从局部(两个独立区域之间)上来看是基于“复制”算法来实现的。无论如何,这两种算法都意味着G1运行期间不会产生内存空间碎片,收集后能提供规整的可用内存。有利于程序的长时间持续运行。
四、可预测的停顿:G1除了追求低停顿之外,还可以建立可以预测的停顿时间模型,能让使用者明确指定在一个长度为M毫秒的时间片段内,消耗的在垃圾收集的时间不超过N毫秒。1
深入理解Java虚拟机 ↩︎
最后
以上就是合适柜子为你收集整理的JVM垃圾收集器分类JVM垃圾收集器分类的全部内容,希望文章能够帮你解决JVM垃圾收集器分类JVM垃圾收集器分类所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复