JVM垃圾收集器总结

0 篇文章 0 订阅

HotSpot JVM收集器

上面有7中收集器,分为两块,上面为新生代收集器,下面是老年代收集器。如果两个收集器之间存在连线,就说明它们可以搭配使用。

收集器
 
回收区域
特性
回收算法
使用场景
Serial(串行GC)-XX:+UseSerialGC新生代

历史最悠久

单线程,进行垃圾收集时,必须暂停其他所有工作线程“Stop The World”

简单、高效,无线程切换开销

复制算法

JVM Client模式下默认的新生代收集器,

桌面应用

ParNew(并行GC)

-XX:+UseParNewGC

-XX:+UseConcMarkSweepGC

新生代

多线程收集,默认开启收集线程数与CPU的数量相同,

-XX: ParallelGCThreads,限制垃圾收集线程数

复制算法Server模式下新生代收集器,首要选择

Parallel Scavenge

(并行回收GC)

-XX:+UseParallelGC(Parallel Scavenge +  Serial Old)

-XX:+UseParallelOldGC( Parallel Scavenge +  Parallel Old)

 

新生代

吞吐量优先:

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

吞吐量= 程序运行时间/(程序运行时间 + 垃圾收集时间)

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

 

提供两个精确控制吞吐量的参数:

-XX:MaxGCPauseMills 控制最大垃圾收集停顿时间,

-XX:GCTimeRatio 设置吞吐量大小,默认值99

 

-XX:+UseAdaptiveSizePolicy 自适应调节,是Parallel Scavenge和ParNew的重要区别

复制算法后台运算,不需要太多交互的任务
Serial Old(串行GC)-XX:+UseParallelGC(Parallel Scavenge +  Serial Old)老年代

单线程

与Parallel Scavenge配合

作为CMS的后备预案,在并发收集发生Concurrent Mode Failure时使用

标记-整理

Client模式

 

Parallel Old(并行GC)-XX:+UseParallelOldGC( Parallel Scavenge +  Parallel Old)老年代

多线程

吞吐量优先

标记-整理吞吐量优先,CPU资源敏感
CMS(并发GC)-XX:+UseConcMarkSweepGC老年代

目的:获取最短回收停顿时间

CMS收集器的内存回收过程是与用户线程一起并发执行的。
CMS收集器的优点:
并发收集、低停顿
三个缺点:
1)CMS收集器对CPU资源非常敏感。
2)CMS收集器无法处理浮动垃圾,可能出现“Concurrent Mode Failure“,失败后而导致另一次Full  GC的产生。由于CMS并发清理阶段用户线程还在运行,伴随程序的运行自热会有新的垃圾不断产生,这一部分垃圾出现在标记过程之后,CMS无法在本次收集中处理它们,只好留待下一次GC时将其清理掉。这一部分垃圾称为“浮动垃圾”。也是由于在垃圾收集阶段用户线程还需要运行,
即需要预留足够的内存空间给用户线程使用,因此CMS收集器不能像其他收集器那样等到老年代几乎完全被填满了再进行收集,需要预留一部分内存空间提供并发收集时的程序运作使用。在默认设置下,CMS收集器在老年代使用了68%的空间时就会被激活,也可以通过参数-XX:CMSInitiatingOccupancyFraction的值来提供触发百分比,以降低内存回收次数提高性能。要是CMS运行期间预留的内存无法满足程序其他线程需要,就会出现“Concurrent Mode Failure”失败,这时候虚拟机将启动后备预案:临时启用Serial Old收集器来重新进行老年代的垃圾收集,这样停顿时间就很长了。所以说参数-XX:CMSInitiatingOccupancyFraction设置的过高将会很容易导致“Concurrent Mode Failure”失败,性能反而降低。
3)CMS是基于“标记-清除”算法实现的收集器,使用“标记-清除”算法收集后,会产生大量碎片。空间碎片太多时,将会给对象分配带来很多麻烦,比如说大对象,内存空间找不到连续的空间来分配不得不提前触发一次Full  GC。为了解决这个问题,CMS收集器提供了一个-XX:UseCMSCompactAtFullCollection开关参数,用于在Full  GC之后增加一个碎片整理过程,还可通过-XX:CMSFullGCBeforeCompaction参数设置执行多少次不压缩的Full  GC之后,跟着来一次碎片整理过程。

收集过程分为:

1)初始标记 (stop the world),仅仅只是标记出GC ROOTS能直接关联到的对象,速度很快

2)并发标记,进行GC ROOTS 根搜索算法阶段,会判定对象是否存活

3)重新标记 (stop the world)

4)并发收集

标记-清除互联网站或者B/S系统,交互体验好
G1-XX:+UseG1GC 

G1收集器基于“标记-整理”算法实现,也就是说不会产生内存碎片

G1垃圾收集的范围是整个Java堆(包括新生代,老年代)

化整为零,G1把整个堆划分成若干Region,后台维护一个优先列表,每次根据允许的收集时间,优先回收价值最大的Region(Gargage-First的由来)

 

收集过程分为:

1)初始标记 (stop the world)

2)并发标记

3)最终标记

4)筛选回收

标记-整理面向服务端应用,目的是替代CMS

JVM启动参数共分为三类: 

        其一是标准参数(-),所有的JVM实现都必须实现这些参数的功能,而且向后兼容; 
        其二是非标准参数(-X),指的是JVM底层的一些配置参数,这些参数在一般开发中默认即可,不需要任何配置。但是在生产环境中,并不保证所有jvm实现都满足,所以为了提高性能,往往需要调整这些参数,以求系统达到最佳性能。
                                           另外这些参数不保证向后兼容,也即是说“如有变更,恕不在后续版本的JDK通知”(这是官网上的原话); 
        其三是非Stable参数(-XX),这类参数在jvm中是不稳定的,不适合日常使用的,后续也是可能会在没有通知的情况下就直接取消了,需要慎重使用。 

 

Full GC
        除CMS GC外,当旧生代和持久化触发GC时,其实是对新生代、旧生代及持久代都进行GC,因此通常又称为Full GC。
        当Full GC被触发时,首先按照新生代所配置的GC方式对新生代进行GC(在新生代采用PS GC时,可通过-XX:-ScavengeBeforeFullGC来禁止Full GC时对新生代进行GC),然后按照旧生代的GC方式对旧生代、持久代进行GC。但其中有一种特殊现象,如在进行Minor GC前,可能Minor GC后移到旧生代的对象多于旧生代的剩余空间,这种情况下Minor GC就不会执行了,而是直接采用旧生代的GC方式来对新生代、旧生代及持久代进行回收。 
 
除System.gc,触发Full GC的情况

1) 旧生代空间不足

    旧生代空间只有在新生代对象转入及创建为大对象、大数组时才会出现不足的现象,当执行Full GC后空间仍然不足,则抛出如下错误:

    java.lang.OutOfMemoryError: Java heap space 

   为避免以上两种状况引起的Full GC,调优时应尽量做到让对象在Minor GC阶段被回收、让对象在新生代多存活一段时间及不要创建过大的对象及数组。

2) Perman Generation空间满

    Perman Generation中存放的为一些class的信息等,当系统中要加载的类、反射的类和调用的方法较多时,Perman Generation可能会被占满,在未配置为采用CMS GC的情况下会执行Full GC。如果经过Full GC仍然回收不了,那么JVM会抛出如下错误信息:

    java.lang.OutOfMemoryError: PermGen space 

    为避免Perm Gen占满造成Full GC现象,可采用的方法为增大Perm Gen空间或转为使用CMS GC。

3) CMS GC时出现promotion failed和concurrent mode failure

    对于采用CMS进行旧生代GC的程序而言,尤其要注意GC日志中是否有promotion failed和concurrent mode failure两种状况,当这两种状况出现时可能会触发Full GC。

    promotion failed是在进行Minor GC时,survivor space放不下、对象只能放入旧生代,而此时旧生代也放不下造成的;

    concurrent mode failure是在执行CMS GC的过程中同时有对象要放入旧生代,而此时旧生代空间不足造成的。

    应对措施为:增大survivor space、旧生代空间或调低触发并发GC的比率,但在JDK 5.0+、6.0+的版本中有可能会由于JDK的bug29导致CMS在remark完毕后很久才触发sweeping动作。

    对于这种状况,可通过设置-XX: CMSMaxAbortablePrecleanTime=5(单位为ms)来避免。

4)  统计得到的Minor GC晋升到旧生代的平均大小大于旧生代的剩余空间

    这是一个较为复杂的触发情况,Hotspot为了避免由于新生代对象晋升到旧生代导致旧生代空间不足的现象,在进行Minor GC时,做了一个判断,如果之前统计所得到的Minor GC晋升到旧生代的平均大小大于旧生代的剩余空间,那么就直接触发Full GC。

    例如程序第一次触发Minor GC后,有6MB的对象晋升到旧生代,那么当下一次Minor GC发生时,首先检查旧生代的剩余空间是否大于6MB,如果小于6MB,则执行Full GC。

     当新生代采用PS GC时,方式稍有不同,PS GC是在Minor GC后也会检查,例如上面的例子中第一次Minor GC后,PS GC会检查此时旧生代的剩余空间是否大于6MB,如小于,则触发对旧生代的回收。

除了以上4种状况外,对于使用RMI来进行RPC或管理的Sun JDK应用而言,默认情况下会一小时执行一次Full GC

可通过在启动时通过- java -Dsun.rmi.dgc.client.gcInterval=3600000来设置Full GC执行的间隔时间

通过-XX:+ DisableExplicitGC来禁止RMI调用System.gc

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值