垃圾收集器

垃圾收集器

并行(Parallel):指多条垃圾收集线程并行工作,但此时用户线程扔然处于等待状态。

并发(Concurrent):指用户线程与垃圾收集线程同时执行,但不一定是并行,可能会交替执行)

Serial收集器

单线程收集器,在进行垃圾收集时,会暂停其他所有的工作线程,直到它收集结束,”Stop The World”,属于新生代收集器

优点:

  1. 简单高效(与其他收集器的单线程比),没有线程交互的开销,专心做垃圾收集,获得最高的单线程收集效率
  2. 对于用户的桌面应用场景,分配给虚拟机的内存一般来说不会很大,收集几十兆甚至一两百兆的新生代,停顿时间完全可以控制在几十毫秒最多一百毫秒以内,只要不是频繁发生,都是可接受的,所以该收集器在Client模式下是很好的选择

ParNew收集器

Serial收集器的多线程版本,除了使用多线程之外,其余所有控制参数、收集算法、回收策略都与Serial收集器完全一样,属于新生代收集器

  1. 许多运行在Server模式下的虚拟机中首选的新生代收集器,除了Serial收集器,目前只有它能和CMS收集器配合工作

Parallel Scavenge收集器

Parallel Scavenge收集器也是作用于新生代,与其他新生代全部类似,区别在于其目的是达到一个可控制的吞吐量.

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

虚拟机总共运行了100分钟,其中垃圾收集花掉1分钟,那吞吐量就是99%

优势:

停顿时间越短约适合需要与用户交互的程序,而高吞吐量则可以高效率地利用CPU时间,尽快完成程序的运算任务,主要适合在后台运算而不需要太多交互的任务

参数

Parallel Scavenge收集器提供了两个参数用于精确控制吞吐量,通常被称为”吞吐量优先”收集器

控制最大垃圾收集停顿时间

-XX:MaxGCPauseMillis

MaxGCPauseMillis参数允许的值是一个大于0的毫秒数,收集器将尽可能地保证内存会受花费的时间不超过设定值,但是不是说越小越好,GC停顿时间缩短是以牺牲吞吐量和新生代空间来换取的:系统把新生代调小一些,收集300MB新生代肯定比500MB快,这也直接导致垃圾收集更加频繁,原来10秒收集一次、每次停顿100毫秒,现在变成5秒收集一次,每次停顿70毫秒。停顿时间的确下降了,但是吞吐量也降低了。

直接设置吞吐量大小

-XX:GCTimeRatio

大于0小于100的整数,也就是垃圾收集时间占总时间的比率,相当于吞吐量的导数

如果把此参数设置为19,允许最大的GC时间就占总时间的5%(即1/(1+19)),默认为99,就是允许最大1%的垃圾收集时间

自适应调节策略

-XX:UseAdaptiveSizePolicy

这是一个开关参数,当打开滞后,就不需要指定新生代的大小(-Xmn)、Eden与Survivor区的比例(-XX:SurvivorRatio)、晋升老年代对象年龄(-XX:PreternureSizeThreshold)等细节参数了.

系统会根据当前系统的运行情况收集性能监控信息,动态调整这些参数以提供最合适的停顿时间或者最大吞吐量。

如果对收集器运行原理不太了解,这是个不错的选择,只要设置好最大堆(-Xmx),然后选择关注最大停顿时间还是关注吞吐量,给虚拟机设立一个优化目标,那么具体细节参数的调节工作就交由虚拟机完成了

Serial Old收集器

是Serial收集器的老年代版本,同样是一个单线程收集器,使用”标记-整理算法”,这个收集器的主要意义也是在于给Client模式下的虚拟机使用,如果在Server模式下,它主要还有两大用途

  1. JDK1.5以及之前的版本中与Parallel Scavenge收集器配合使用
  2. 作为CMS收集器的后备预案,在并发收集发生Concurrent Mode Failure时使用

Parallel Old收集器

是Parallel Scavenge收集器的老年代版本,使用多线程和”标记-整理”算法, 这个收集器在JDK1.6中才开始提供,在注重吞吐量以及CPU资源敏感的场合,都可以优先考虑Parallel Scavenge加Parallel Old收集器

CMS收集器

CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器,基于”标记-清除”算法实现,它的整个过程分为4个步骤,包括:

  1. 初始标记(CMS initial mark)
  2. 并发标记(CMS concurrent mark)
  3. 重新标记(CMS remark)
  4. 并发清除(CMS)

其中,初始标记、重新标记两个步骤仍然需要 Stop the World。初始标记仅仅只是标记一下GC ROOTS能关联到的对象,速度很快,并发标记就是进行GC ROOTS Tracing的过程,而重新标记则是为了修正并发标记期间因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录,这个阶段的停顿时间比初始标记长,远短于并发标记

缺点:

  1. 并发设计对CPU非常敏感,会因为一部分线程的占用导致应用程序变慢,总吞吐量降低
  2. 无法处理浮动垃圾,可能会出现”Concurrent Mode Failure”失败而导致另一次Full GC的产生
  3. 由于CMS属于标记-清除算法,这意味着收集结束时会有大量空间碎片产生

参数

-XX:+UseCMSCompactAtFullCollection

开关参数,默认开启,用于在CMS收集器顶不住要进行Full GC时开启内存碎片的合并整理过程,内存整理的过程是无法并发的,内存碎片问题没有了,但是停顿时间不得不变长,因此有下面的参数

-XX:CMSFullGCsBeforeCompaction

这个参数用于设置执行多少次不压缩的Full GC后,跟着来一次带压缩的,默认值0,表示每一次进行Full GC时都进行碎片整理

G1收集器

JDK 1.7中新引入的垃圾收集器,可以用来替代CMS,与其他垃圾收集器相比,G1具备如下特点

  1. 并行与并发: 能充分利用多CPU、多核环境下的硬件优势,来缩短Stop-The-World停顿的时间
  2. 分代收集:虽然G1可以不需要其他收集器配合就能独立管理整个GC堆,但它能够采用不同的方式去处理新创建的对象和已经存活了一段时间的旧对象以获取更好的收集效果。
  3. 空间整合:与CMS的标记清理算法不同,G1从整体上看来是基于标记整理算法实现的收集器,从局部上来看(两个Region之间)是基于复制算法实现的,但是这都意味着G1运作期间不会产生
  4. 可预测的停顿:这是G1相对于CMS的灵一大优势,G1除了追求低停顿外,还能建立可预测的停顿时间模型,能让使用者明确指定在一个长度为M毫秒的时间片段内,消耗在垃圾收集上的时间不得超过N毫秒

在G1之前其他收集器进行收集的范围都是整个新生代或者老年代,而使用G1收集器时,整个内存就被划分为多个大小相等的独立区域(Region),虽然还保留着新生代和老年代的概念,但是不再是物理隔离的了,它们都是一部分Region(不需要连续)的集合

G1收集器之所以能建立可预测的停顿时间模型,是因为G1根本各个Region里面的垃圾堆积的价值大小(回收所获得的空间大小以及回收所需时间),在后台维护一个优先列表,每次优先回收价值最大的Region,这也是Garbage-First的由来