fullgc过于频繁有可能会造成oom,有可能不会。
首先明确一下,这篇文章的重点是分析后面一种情况,即应用在频繁的fullgc,但并没有出现oom。
我们来想一下为什么会出现fullgc,触发原因有很多种,但归根到底都是因为内存空间不足了(system.gc的情况不考虑)。
系统在频繁的fullgc,但并没有出现oom,说明每次回收的时候,肯定清理了部分内存空间。那这里就有2种情况,gc之后清理的内存空间大不大?
1、如果每次gc之后剩余的空间不大,说明有一部分顽固对象一直没法被回收,导致可用内存变少。这种情况下很容易后续出现oom,比如说一次大对象的申请
2、如果每次gc之后剩余的空间比较大,意味着大部分对象都被清理了,但是系统又在频繁的fullgc,说明很快老年代又会涌入大量对象。这个时候就应该检查下jvm的参数配置,很有可能是新生代设置的太小了,导致很多应该在minor gc阶段就清理出去的对象留到了老年代,这种可能性是最大的
新生代可以分为eden、survivor0、survivor1,正常的对象分配都是在eden完成的,如果eden空间不够了,会触发一次minor gc,存活的对象放在s0或s1中。随着每次minor gc,存活的对象会不断的从s0迁到s1,再从s1迁到s0,这个过程经过几次之后,如果对象还是存活的,就会晋升到老年代。
但如果新生代大小设置的太小,就会导致非常频繁的minor gc,s0->s1来回切换的速度加快,导致本身应该在minor gc就清理出去的对象跑到了老年代。
举个例子,正常情况下如果minor gc是1分钟一次,-XX:MaxTenuringThreshold默认配置是15的话,正常的小对象最长可以在新生代待15分钟左右,如果一个对象o的存活时间是5分钟,那它就可以在minor gc的时候被清理出去;但如果新生代设置过小,minor gc的频率降到10秒一次,那么o只能在新生代待150秒左右,然后就会晋升到老年代,这种对象一多,就会导致频繁的fullgc
=====================================
FullGC触发条件:
老年代空间不足
存在情况
每次晋升到老年代的对象平均大小 > 老年代剩余空间
MinorGC后存活的对象超过了老年代剩余空间
优化策略
调优时应尽量做到让对象在Minor GC阶段被回收、让对象在新生代多存活一段时间及不要创建过大的对象及数组
永久代(方法区)空间不足
简介
JVM规范中运行时数据区域中的方法区,在HotSpot虚拟机中又被习惯称为永久代,Permanet Generation中存放的为一些class的信息、常量、静态变量等数据,当系统中要加载的类、反射的类和调用的方法较多时,Permanet Generation可能会被占满,在未配置为采用CMS GC的情况下也会执行Full GC。
解决方案
避免Perm Gen占满造成FullGC现象,可采用的方法为增大Perm Gen空间或转为使用CMS GC
System.gc()
简介
此方法的调用是建议JVM进行Full GC,虽然只是建议而非一定,但很多情况下它会触发Full GC,从而增加Full GC的频率,即增加了间歇性停顿的次数。强烈影响系建议能不使用此方法就别使用,让虚拟机自己去管理它的内存,通过-XX:+ DisableExpllicitGC来禁止RMI调用System.gc。
CMS GC异常
JVM GC算法CMS详解
https://www.cnblogs.com/lishiqi-blog/p/11899094.html
简介
CMS,全称Concurrent Low Pause Collector。CMS是用于对tenured generation的回收,也就是年老代的回收,目标是尽量减少应用的暂停时间,减少full gc发生的几率,利用和应用程序线程并发的垃圾回收线程来标记清除年老代。
收集周期
CMS并非没有暂停,而是用两次短暂停来替代串行标记整理算法的长暂停,它的收集周期是这样:
初始标记(CMS-initial-mark) -> 并发标记(CMS-concurrent-mark) -> 重新标记(CMS-remark) -> 并发清除(CMS-concurrent-sweep) ->并发重设状态等待下次CMS的触发(CMS-concurrent-reset)。
常见异常
promotion failed:MinorGC时,survivor空间放不下,对象只能放入老年代,而老年代也放不下造成
concurrent mode failure: 在执行CMS GC的过程中同时有对象要放入旧生代,而此时旧生代空间不足造成的。
堆内存分配很大的对象
简介
所谓大对象,是指需要大量连续内存空间的java对象,例如很长的数组,此种对象会直接进入老年代,而老年代虽然有很大的剩余空间,但是无法找到足够大的连续空间来分配给当前对象,此种情况会触发JVM进行FullGC
解决方案
CMS垃圾收集器提供了一个可配置参数,即-XX:+UseCMSCompactAtFullCollection开关参数,用于在"享受"完FullGC后额外免费赠送一个碎片整理的过程,内存整理的过程无法并发的,空间碎片问题没有了,但停顿时间不得不变长。
JVM设计者们还提供了另外一个参数 -XX:CMSFullGCsBeforeCompaction,用于设置在执行多少次不压缩的FullGC后,跟着来一次带压缩的