垃圾收集器

Posted gqymy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了垃圾收集器相关的知识,希望对你有一定的参考价值。

技术图片

 

 

上面7种作用于不同分代的收集器,如果两个收集器之间存在连线,就说明它们可以搭配使用。虚拟机所处的区域,则标识它是属于新生代收集器还是老年代收集器。
 
Serial收集器:
        Serial收集器是最基本、发展历史最悠久的收集器,曾经(JDK1.3.1前)是虚拟机新生代收集器的唯一选择。它是一个单线程的收集器,但它的单线程的意义是在它进行垃圾收集时,必须暂停其他所有的工作线程,直到它收集结束。
        优势:简单而高效,对于限定单个CPU的环境来说,Serial收集器由于没有线程交互的开销,专心做垃圾收集自然可以获得最高的单线程收集效率。在用户的桌面应用场景种,分配给虚拟机管理的内存一般来说不会很大,收集几十兆甚至一两百兆的新生代,停顿时间完全可以控制在几十毫秒最多一百毫秒以内,只要不是频繁发生,这点停顿是可以接受的。所以Serial收集器对于运行在Client模式下的虚拟机来说是一个很好的选择
 
ParNew收集器:
        ParNew收集器其实就是Serial收集器的多线程版本,除了使用多线程进行垃圾收集之外,其余行为包括Serail收集器可用的所有控制参数、收集算法、Stop the World、对象分配规则、回收策略等都与Serial收集器完全一样
        ParNew收集器除了多线程收集之外,其他与Serial收集器相比并没有太多创新之处,但它却是许多运行在Server模式下的虚拟机种首选的新生代收集器,其中有一个与性能无关但却很重要的原因是,除了Serial收集器外,目前只有它能与CMS收集器配合工作。在JDK1.5时,HotSpot推出了一款在强交互应用中几乎认为有划时代意义的垃圾收集器——CMS收集器,这款收集器是HotSpot虚拟机中第一款真正意义上的并发收集器,它第一次实现了让垃圾收集线程与用户现场同时工作。
        ParNew收集器在单CPU的环境中绝对不会有比Serial收集器更好的效果,甚至优于存在线程交互的开销,该收集器在通过超线程技术实现的两个CPU的环境中都不能百分之百地保证可以超越Serail收集器
 
Parallel Scavenge收集器:
        Parallel Scavenge收集器是一个新生代收集器,它也是使用复制算法的收集器,又是并行的多线程收集器
        特点是它的关注点与其他收集器不同,CMS等收集器的关注点是尽可能地缩短垃圾收集时用户线程的停顿时间,而Parallel Scavenge收集器的目标则是达到一个可控制的吞吐量,也就是CPU用于运行用户代码的时间与CPU总消耗时间的比值,即 吞吐量 = 运行用户代码时间 / (运行用户代码时间 + 垃圾收集时间),虚拟机总共运行了100分钟,其中垃圾收集花掉1分钟,那么吞吐量就是99%
 
Serial Old收集器
        Serial Old是Serial收集器的老年代版本,它同样是一个单线程收集器,使用 标记-整理 算法。这个收集器的主要以一也是在于给Client模式下的虚拟机使用。如果在Server模式下,那么它主要还有两大用途:一种用途是在JDK1.5以及之前的版本中与Parallel Scavenge收集器搭配使用,另一种用途就是作为CMS收集器的后被元,在并发手机发生Concurrent Mode Failure时使用。
 
Parallel Old收集器:
        Parallel Old时Parallel Scavenge收集器的老年代版本,使用多线程和 标记-整理 算法。这个收集器是在JDK1.6中才开始提供的,如果新生代选择了Parallel Scavenge收集器,老年代除了Serial Old收集器外别无选择。由于老年代Serial Old收集器在服务端应用性能上的拖累,使用了Parallel Scavenge收集器也未必能在整体应用上获得吞吐量最大化的效果,由于单线程的老年代收集中无法充分利用服务器多CPU的处理能力,在老年代很大而且硬件比较高级的环境中,这种组合的吞吐量甚至还不一定有ParNew加CMS的组合给力
 
CMS收集器:
        CMS收集器是一种以获取最短回收停顿时间位目标的收集器。CMS收集器是基于 标记-清除 算法实现的,整个过程分为4个步骤,包括:
                初始标记
                并发标记
                重新标记
                并发清除
 
        初始标记、重新标记这两个步骤仍然需要“Stop The World”。初始标记仅仅只是标记一下GC Roots能直接关联到的对象,速度很快,并发标记阶段就是进行GC Roots Tracing的过程,而重新标记阶段则是为了修正并发标记期间因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录,这个阶段的停顿时间一般回避初始标记阶段稍长一些,但远比并发标记的时间段
        缺点:    
                    1.CMS收集器对CPU资源非常敏感,在并发阶段,它虽然不会导致用户线程停顿,但是会因为占用了一部分线程(CPU资源)而导致应用程序变慢,总吞吐量会降低。CMS默认启动的回收线程数是(CPU数量+3)/4,也就是说当CPU在4个以上时,并发回收时垃圾收集线程不少于25%的CPU资源,并且随着CPU数量的增加而下降。但是当CPU不足4个时,CMS对用户程序的影响就可能变得很大,如果本来CPU负载就比较大,还分出一半的运算能力区执行收集器线程,就可能导致用户程序的执行速度忽然降低了50%,其实也让人无法接受。为了应付这种情况,虚拟机提供了一种称为“增量式并发收集器”的CMS收集器变种,就是在并发标记、清理的时候让GC线程、用户线程交替运行,尽量减少GC线程的独占资源的时间。
                    2,CMS收集器无法处理浮动垃圾,可能出现“Concurrent Model Failure”失败而导致另一次FULL GC的产生。由于CMS并发清理阶段用户线程还在运行着,伴随程序运行自然就还会有新的垃圾不断产生,这一部分垃圾出现在标记过程之后,CMS无法在当次收集中处理掉它们,只好留待下一次GC时再清理掉。这一部分垃圾就称为浮动垃圾。也是由于在垃圾收集阶段用户线程还需要运行,那也就还需要预留有足够的内存空间给用户线程使用,因此CMS收集器不能像其他收集器那样等到老年代几乎完全被填满了再进行手机,需要与留一部分空间提供并发收集时的程序运作使用。
                    3.CMS是一款基于“标记-清除”算法实现的收集器,收集结束时会有大量的空间碎片产生。空间碎片过多时,将会给大对象分配带来很大麻烦,往往会出现老年代还有很大空间剩余,但是无法找到大的连续空间来分配当前对象,不得不提前触发一次FuLL GC。为了解决这个问题,CMS收集器提供了一个-XX:UseCMSCompactAtFullCollection开关参数,用于在CMS收集器顶不住要进行FullGC时开启内存碎片的合并整理过程,内存整理的过程是无法并发的,空间碎片问题没有了,但停顿时间不得不变长。虚拟机设计者还提供了另外一个参数-XX:CMSFullGCsBeforeCompaction,这个参数是用于设置执行多少次不压缩的Full GC后,跟着来一次带压缩的
 
G1收集器:
                G1是一款面向服务端应用的垃圾收集器。HostSpot开发团队赋予它的使命是替换掉jdk1.5中的CMS收集器。
        特点:
                    并行与并发:G1能充分利用多CPU、多核环境下的硬件优势,使用多个CPU来缩短Stop-The-World停顿的时间,部分其他收集器原本需要停顿Java线程执行的GC动作,G1收集器仍然可以通过并发的方式让Java程序继续执行。
                    分代收集:与其他收集器一样,分代概念在G1中得以保留。虽然G1可以不需要其他收集器配合就能独立管理整个GC堆,但它能够采用不同的方式区处理新创建的对象和已经存活了一段时间、熬过多次GC的旧对象以获取更好的手机效果
                    空间整合:与CMS的“标记-清理”算法不同,G1从整体来看是基于“标记-整理”算法实现的收集器,从局部上来看是基于“复制”算法实现的,但无论如何,这两种算法都意味着G1运作期间不会产生内存空间水平,收集后能提供规整的可用内存。这种特性有利于程序长时间运行,分配大对象时不会因为无法找到连续内存空间而提前触发下一次GC
                    可预测的停顿:这是G1相对于CMS的另一大优势,降低停顿时间是G1和CMS共同的关注点,但G1除了追求降低停顿外,还能建立可预测的停顿时间模型,能让使用者明确指定在一个长度为M毫秒的时间片段内,消耗在垃圾收集上的时间不得超过N毫秒,这几乎已经是实时Java的垃圾收集特征了

以上是关于垃圾收集器的主要内容,如果未能解决你的问题,请参考以下文章

垃圾收集器(垃圾收集算法的实现)

垃圾收集器(垃圾收集算法的实现)

JVM之垃圾收集算法与垃圾收集器

JVM垃圾收集—垃圾收集器及常见组合参数

G1垃圾收集器介绍

JVM垃圾收集器