JVM垃圾收集器

 仅以此记录学习笔记等!

HostSpot虚拟机中的垃圾收集器

JVM垃圾收集器

注:两个收集器之间存在连线,说明其可以搭配使用。特殊说明:CMS备选老年代收集器可以使用Serial Old。

 

Serial收集器

-XX:+UseSerialGC

简介:Serial收集器是最基本、发展历史最悠久的垃圾收集器,曾是虚拟机新生代收集的唯一选择。

Serial串行的、连续的,很明显其代表的是一个单线程收集器。但它的“单线程”的意义并不仅仅说明它只会使用一个CPU或者一条垃圾收集线程去完成垃圾收集工作,更重要的是它在进行垃圾回收的时候,必须暂停其所有的工作线程(STW),直到它收集结束。

 

工作运行图:Serial组合Serial Old

JVM垃圾收集器

注:新生代、老年代都是单线程

缺点:Stop The World给用户带来的不良体验,为消除或者减少工作线程因为内存回收而导致停顿的努力一直进行着,所以有了后续的垃圾收集器的出现,但是仍然没办法完全消除。

优点:与其它单线程收集器相比,其简单而高效。因为Serial没有线程交互的开销,自然可以拥有高效的单线程收集效率。

 

Serial Old收集器

-XX:+UseSerialOldGC

简介:如一开始的收集器连接图,Serial Old收集器是Serial新生代收集器的老年代版本,它同样是一个单线程的收集器,使用的是“标记-整理”算法。其主要意义是给Client模式下的虚拟机使用。

如果在Server 模式下,它有两大用途:

  • 在JDK1.5以及之前的版本中与Parallel Scavenge收集器搭配使用

  • 作为CMS收集器的后备预案

 

工作图与Serial收集器一致。

 

ParNew收集器

简介:ParNew收集器其实就是Serial收集器的多线程版本,除了使用多条线程进行垃圾收集之外,还包括Serial收集器的控制参数

-XX:+UseParNewGC

-XX:+SurvivorRatio 设置新生代内存的占比

-XX:PretenureSizeThreshold 可直接进入老年代对象大小

-XX:HandlePromotionFailure 老年代空间担保机制开启

以及收集算法,STW,对象分配规则、回收策略等都与Serial收集器其完全一致。

 

它是运行在Server模式下的新生代收集器的首选,除了Serial收集器之外,目前只有它能够和CMS收集器配合工作

 

工作运行图:ParNew 组合 Serial Old

JVM垃圾收集器

注:新生代多线程,老年代单线程

 

Parallel Scavenge收集器

简介:Parallel Scavenge收集器是一个新生代的收集器,也是使用复制算法的收集器,又是并行的多线程收集器。

其特点是它的关注点与其它收集器不同,CMS等收集器是尽可能地缩短垃圾收时用户线程的停顿时间,而Parallel Scavenge的目标则是达到一个可以控制的吞吐量(Throughput)。

所谓吞吐量就是CUP用于运行代码的时间与CPU总耗时间的比值,即吞吐量=运行用户代码时间/(运行用户代码时间+垃圾收集时间)。

Parallel Scavenge提供了多个参数用于找到合适的吞吐量或停顿时间。

-XX:MaxGCPauseMillis 控制最大垃圾收集停顿时间ms

-XX:GCTimeRatio 设置吞吐量大小(垃圾收集时间大小)(0-100的整数,默认99) 假设此参数设置为19,那允许的最大GC时间就占总时间的5%(即 1/(1+19))

 

Parallel Old

Parallel Old是Parallel Scavenge的老年代版本,使用多线程和“标记-整理”算法。JDK1.6所提供。一般以吞吐量以及CPU为资源敏感的场合下,都可以优先考虑Parallel Scavenge加Parallel Old的组合。

 

工作运行图:Parallel Scavenge 组合 Parallel Old

JVM垃圾收集器

注:新生代、老年代都是多线程运行GC

 

CMS收集器

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

从名字(“Mark Sweep”)可以看出,CMS收集器是基于“标记-清除”算法实现的。

整个过程包括四个步骤:

      • 初始标记(initial mark):需要暂停所有线程(STW),标记以下GC ROOTS能直接关联到的对象,速度很快。

      • 并发标记(concurrent mark):指的是从GC ROOTS的直接关联对象开始遍历整个对象图的过程,这个过程耗时较长(占用总时间80%左右),但是不需要STW,可以与垃圾收集线程一起并发运行。因为用户程序继续运行,可能会导致已经标记过的对象状态发生改变。

      • 重新标记(remark):需要暂停所有线程(STW)。指的是为了修正并发标记期间因为用户程序继续运行而导致标记产生变动的那一部分对象的标记记录,而且这个停顿时间一般会比初始标记的时间稍长,远远比并发标记的时间短。(三色标记)

      • 并发清除(concurrent sweep):开启用户线程,同时GC线程开始对未标记的区域做清扫。这个阶段如果有新增对象会被标记为黑色不做任何处理。(三色标记)

      • 并发重置(reset):重置本次GC过程中的标记数据。

工作运行图:

JVM垃圾收集器

优点:

  • 并发收集

  • 低停顿感,将停顿分为好几次,给用户零感触

缺点:

    • 对CPU资源敏感。在并发阶段,它虽然不会导致用户线程停顿,但是会因为占用了一部分线程(或者说CPU资源)而导致应用程序变慢,总吞吐量会降低。如果CPU数量较少时,如2个CPU,需要分出一半的运算能力区执行收集器线程,就会导致用户程序的执行速度忽然降低50%。

    • 无法处理浮动垃圾。在并发标记和并发清理阶段又产生的垃圾,这种垃圾会导致另一次Full GC的产生,即下一次gc处理。

    • 接上一点。如果在运行期间预留的内存无法满足程序需要时,就会出现一次“Concurrent Mode Failure”并发失败。即在上一次垃圾回收还没执行完时,然后垃圾回收又被触发的情况,特别是产生浮动垃圾的时候(并发标记和并发清理阶),一边回收,系统一边运行,没回收完就再次触发了Full GC,此时就会进入STW,临时启用Serial Old收集器来重新进行老年代的垃圾收集,这里会一直等待收集完成(等待时间很长)。

    • 基于“标记-清除”的算法,会导致收集结束时会有大量空间碎片产生。空间碎片过多,给大对象分配内存带来很大麻烦,如果没有内存则会触发Full GC。

      解决:-XX:+UseCMSCompactAtFullCollection 默认开启,用于CMS在顶不住要进行Full GC时开启内存随便的合并整理过程。配合-XX:CMSFullGCsBeforeCompaction使用。

       

      CMS的相关核心参数

      \1. -XX:+UseConcMarkSweepGC:启用cms

      \2. -XX:ConcGCThreads:并发的GC线程数

      \3. -XX:+UseCMSCompactAtFullCollection:FullGC之后做压缩整理(减少碎片)

      \4. -XX:CMSFullGCsBeforeCompaction:多少次FullGC之后压缩一次,默认是0,代表每次FullGC后都会压缩一

      \5. -XX:CMSInitiatingOccupancyFraction: 当老年代使用达到该比例时会触发FullGC(jdk1.6默认是92,这是百分比)

      \6. -XX:+UseCMSInitiatingOccupancyOnly:只使用设定的回收阈值(-XX:CMSInitiatingOccupancyFraction设

      定的值),如果不指定,JVM仅在第一次使用设定值,后续则会自动调整

      \7. -XX:+CMSScavengeBeforeRemark:在CMS GC前启动一次minor gc,目的在于减少老年代对年轻代的引

      用,降低CMS GC的标记阶段时的开销,一般CMS的GC耗时 80%都在标记阶段

      \8. -XX:+CMSParallellnitialMarkEnabled:表示在初始标记的时候多线程执行,缩短STW

      \9. -XX:+CMSParallelRemarkEnabled:在重新标记的时候多线程执行,缩短STW;

上一篇:SQL基础知识


下一篇:MySQL详述