触发JVM进行Full GC的情况有哪些

13次阅读
没有评论

这篇文章给大家分享的是有关触发 JVM 进行 Full GC 的情况有哪些的内容。丸趣 TV 小编觉得挺实用的,因此分享给大家做个参考,一起跟随丸趣 TV 小编过来看看吧。

堆内存划分为 Eden、Survivor 和 Tenured/Old 空间,如下图所示:

触发 JVM 进行 Full GC 的情况有哪些

从年轻代空间(包括 Eden 和 Survivor 区域)回收内存被称为 Minor GC,对老年代 GC 称为 Major GC, 而 Full GC 是对整个堆来说的,在最近几个版本的 JDK 里默认包括了对永生带即方法区的回收(JDK8 中无永生带了),出现 Full GC 的时候经常伴随至少一次的 Minor GC, 但非绝对的。Major GC 的速度一般会比 Minor GC 慢 10 倍以上。下边看看有那种情况触发 JVM 进行 Full GC 及应对策略。

1、System.gc() 方法的调用

此方法的调用是建议 JVM 进行 Full GC, 虽然只是建议而非一定, 但很多情况下它会触发 Full GC, 从而增加 Full GC 的频率, 也即增加了间歇性停顿的次数。强烈影响系建议能不使用此方法就别使用,让虚拟机自己去管理它的内存,可通过通过 -XX:+ DisableExplicitGC 来禁止 RMI 调用 System.gc。

2、老年代代空间不足

老年代空间只有在新生代对象转入及创建为大对象、大数组时才会出现不足的现象,当执行 Full GC 后空间仍然不足,则抛出如下错误:
java.lang.OutOfMemoryError: Java heap space 
为避免以上两种状况引起的 Full GC,调优时应尽量做到让对象在 Minor GC 阶段被回收、让对象在新生代多存活一段时间及不要创建过大的对象及数组。

3、永生区空间不足

JVM 规范中运行时数据区域中的方法区,在 HotSpot 虚拟机中又被习惯称为永生代或者永生区,Permanet Generation 中存放的为一些 class 的信息、常量、静态变量等数据,当系统中要加载的类、反射的类和调用的方法较多时,Permanet Generation 可能会被占满,在未配置为采用 CMS GC 的情况下也会执行 Full GC。如果经过 Full GC 仍然回收不了,那么 JVM 会抛出如下错误信息:
java.lang.OutOfMemoryError: PermGen space 
为避免 Perm Gen 占满造成 Full GC 现象,可采用的方法为增大 Perm Gen 空间或转为使用 CMS GC。

4、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 的过程中同时有对象要放入老年代,而此时老年代空间不足造成的(有时候“空间不足”是 CMS GC 时当前的浮动垃圾过多导致暂时性的空间不足触发 Full GC)。
对措施为:增大 survivor space、老年代空间或调低触发并发 GC 的比率,但在 JDK 5.0+、6.0+ 的版本中有可能会由于 JDK 的 bug29 导致 CMS 在 remark 完毕

后很久才触发 sweeping 动作。对于这种状况,可通过设置 -XX: CMSMaxAbortablePrecleanTime=5(单位为 ms)来避免。

5、统计得到的 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。

6、堆中分配很大的对象

所谓大对象,是指需要大量连续内存空间的 java 对象,例如很长的数组,此种对象会直接进入老年代,而老年代虽然有很大的剩余空间,但是无法找到足够大的连续空间来分配给当前对象,此种情况就会触发 JVM 进行 Full GC。

为了解决这个问题,CMS 垃圾收集器提供了一个可配置的参数,即 -XX:+UseCMSCompactAtFullCollection 开关参数,用于在“享受”完 Full GC 服务之后额外免费赠送一个碎片整理的过程,内存整理的过程无法并发的,空间碎片问题没有了,但提顿时间不得不变长了,JVM 设计者们还提供了另外一个参数 -XX:CMSFullGCsBeforeCompaction, 这个参数用于设置在执行多少次不压缩的 Full GC 后, 跟着来一次带压缩的。

感谢各位的阅读!关于“触发 JVM 进行 Full GC 的情况有哪些”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,让大家可以学到更多知识,如果觉得文章不错,可以把它分享出去让更多的人看到吧!