Java JVM 垃圾收集器

Java 的垃圾回收机制最主要的实现者就是”垃圾收集器”,但是每个厂商设计的虚拟机所提供的垃圾收集器都有很大区别,而且即使是同一个虚拟机也会提供几个不同的垃圾收集器供用户根据自己不同特点来组合。

下图是Hot Spot虚拟机包含的收集器,之后介绍每个收集器的特点。
在这里插入图片描述

一、并行和并发的概念

在介绍各种收集器之前,先确认一下并行和并发的概念:(下面是指垃圾收集器的语境中)

  • 并行 ( Parallel ) :多条垃圾收集线程并行工作,但此时用户线程仍然处于等待状态。
  • 并发 ( Concurrent ) :用户线程和垃圾收集线程同时执行(不一定是并行,可能是交替进行的),用户程序继续运行,而垃圾收集程序运行于另一个CPU上。

二、垃圾收集器

2.1、Serial收集器(新生代 – 串行GC)

最基本、最悠久的收集器,他是一个单线程的收集器,而单线程是指当他在进行垃圾收集的时候,必须暂停其他所有的工作线程,被称为 ”Stop The World”。

优点:
简单而高效(与其他收集器的单线程相比),在限于单个CPU的环境,没有额外的线程交互的开销,所以能获得最高效率。

适用:
运行在Client模式下的虚拟机。
在这里插入图片描述

2.2、ParNew收集器(新生代 – 并行GC)

ParNew 收集器 其实就是 Serial收集器的多线程版本,除了使用多条线程进行垃圾收集之外,其余的和Serial所有控制参数一样。
在配置为 CMS GC 的情况下默认的新生代收集器,可以用 -XX:+UseParNewGC 强制指定。

优点:
在多CPU的环境下可以发挥更高而效率,并且是唯一一个可以和CMS收集器搭配工作的新生代并行GC。

适用:
运行在server模式下的虚拟机首选的新生代收集器。

在这里插入图片描述

2.3、Parallel Scavenge收集器(新生代 – 并行回收GC)

看上去和ParNew没什么区别,但是 Parallel Scavenge 最大的特点就是他的关注点在于 CPU的吞吐量

注:吞吐量 = 运行代码时间 /(运行代码时间+垃圾收集时间)

较高的吞吐量可以最好的利用 CPU的效率。-XX:MaxGCPauseMillis 配置最大垃圾收集停顿时间,-XX:GCTimeRatio 配置吞吐量大小。

优点:
被称为”吞吐量优先”收集器,有一个自适应调节参数(-XX:+UseAdaptiveSizePolicy ),当这个参数打开后,无需手动指定新生代大小(-Xmn)、Eden 和 Survivor 比例( -XX:SurvivorRatio )、晋升老年代年龄限制(-XX:PretenureSizeThreshold )等细节参数,虚拟机会动态调节这些参数来提供最适合的停顿时间或最大吞吐量。

适用:
本身是Server级别多CPU机器上的默认GC方式,也可以通过-XX:+UseParallelGC 来指定,并且可以采用 -XX:ParallelGCThread 来指定线程数。

2.4、Serial Old收集器(老年代 – 串行GC)

Serial Old是Serial收集器的年老代版本,同样是一个单线程收集器,使用”标记-整理”算法。

适用:
Client模式下虚拟机使用;在Server模式有两大用途:与Parallel Scavenge收集器搭配使用,作为CMS收集器的后备预案。

2.5、Parallel Old收集器(老年代 – 并行GC)

Parallel Old 是 Parallel Scavenge 收集器的老年代版本,为了配合Parallel Scavenge的面向吞吐量的特性而开发的对应组合。

适用:在注重吞吐量以及CPU资源敏感的场合采用。

在这里插入图片描述

2.6、CMS收集器(老年代 – 并发GC)

CMS ( Concurrent Mark Sweep ) 收集器是一种以获取最短回收 停顿时间 为目标的收集器。

基于 标记-清除 算法 ,整个过程分为4个步骤:

  • 初始标记(CMS initial mark)、
  • 并发标记(CMS concurrent mark)、
  • 重新标记(CMS remark)
  • 并发清除(CMS concurrent sweep)。

其中,初始标记、重新标记仍然是”Stop The World”,

详细说明:

  • 1、初始标记仅仅是标记一下GC Roots能直接关联的对象,
  • 2、并发标记进行GC Roots Tracing的过程,
  • 3、重新标记为了修正并发标记期间因用户程序继续运行而导致标记产生变动的那 部分对象,这个阶段停顿时间比初始标记阶段稍长一些,但比并发标记时间短。
  • 4、并发清除:该阶段 用户线程 和 垃圾清除线程 同时执行(由于清除阶段用户线程还在运行, 自然就会产生新的垃圾(称为“浮动垃圾”), 因为新产生的垃圾在垃圾标记阶段之后,所以这部分新产生的垃圾CMS无法在本次收集过程中处理掉它们,只能留到下次GC时再清理)。

优点:
并发收集、低停顿。

适用:
重视服务的响应速度、系统停顿时间和用户体验的互联网网站或者B/S系统。

缺点:

  • 对CPU资源很敏感:在并发阶段,它虽然不会导致用户线程卡顿,但是因为占用了一部分线程而导致应用程序变慢。
    CMS默认启动的回收线程数量是(CPU的个数+3)/4,如果CPU的个数在4个以上,收集器会占用不少于25%的CPU资源,CPU个数越多,收集器会占用不少于25%的CPU资源,
    CPU个数越多,CPU资源占比越小。但是当CPU不足4(例如2个)的时候,CMS收集器占用一半的运算能力去执行收集器线程。本来CPU负载就比较大,就会导致用户程序的执行效率下降的很明显。

  • 无法处理浮动垃圾:由于最后的垃圾清除阶段是并发进行的,伴随着程序的运行产生的新的垃圾,在本次收集过程中无法处理掉,指的下次GC时再清理。
    而且还需要留足够的内存空间给用户线程使用,不能像其他收集器那样等到老年代几乎被填满了再进行收集,需要预留一部分空间提供并发收集时用户线程使用。

  • 产生大量的空间碎片:CMS是基于“标记-清除”算法实现的收集器。因为这种算法在收集结束后有大量的空间碎片,当碎片过多时,会给大对象的内存分配带来很大麻烦,往往在老年代中还有很大空间剩余,但是无法找到足够大的连续空间来分配当前对象导致不得不提前触发一次Full GC。
    在这里插入‘图片描述

2.7、G1收集器

G1( Garbage First )收集器是当前收集器技术最前沿成果,与之前的CMS相比有两个显著改进:

  • 基于 标记-整理 算法实现收集器
  • 精确控制停顿。

G1收集器 能够在基本不牺牲 吞吐量 的前提下完成 低停顿 的内存回收。

在这里插入图片描述

三、附GC组合

默认GC组合:
在这里插入图片描述

可选的GC组合:

在这里插入图片描述

四、参考资料:

Java虚拟机的JVM垃圾回收机制:
http://blog.csdn.net/zhangren07/article/details/6270895

探秘Java虚拟机——内存管理与垃圾回收:
http://www.blogjava.net/chhbjh/archive/2012/01/28/368936.html

猜你喜欢

转载自blog.csdn.net/xiaojin21cen/article/details/88089688