上一篇主要记录了JAVA的内存模型,主要为虚拟机诠释内存控制的主要概念,是并发场景编程的基础。下面记录一下内存的垃圾回收,是虚拟机性能调优和错误诊断方面的基础。

垃圾在各代上分别回收,年轻代上发生的回收叫Minor GC ,发生一次GC的条件是:Eden 区满。那survivor 区满了怎么办?会发生一次晋升,可能触发一次Major GC/Full GC.MixedGC  是G1收集器中独有的概念,负责部分年轻代和全部老年代的垃圾整理。

Full GC/Major GC 的触发条件有:

  1. 老年代空间不足

这种情况特指创建过大的对象和数组直接分配在老年代分配内存空间时发生,虚拟机有个参数PretenureSizeThreshold,可以控制直接进入老年代的对象大小,需要注意的时该参数只对Serial和ParNew两款收集器有效,Parallel Scavenge收集器不认识这个参数,Parallel Scavenge收集器一般并不需要设置。如果遇到必须使用此参数的场合,可以考虑ParNew加CMS的收集器组合。ParNew是CMS默认使用的年轻代收集器。

      2. 担保失败

如果发现统计数据说之前Minor GC的平均晋升大小比目前old gen剩余的空间大,则不会触发Minor GC而是转为触发full GC. 这也是上面所说的情况.虚拟机参数-XX:+HandlePromotionFailure 控制担保开启。

      3. 晋升失败(老年代空间不足的第二种情况)

由Eden区、From Space区向To Space区复制时,对象大小大于To Space可用内存,则把该对象转存到老年代,且老年代的可用内存小于该对象大小。在配置CMS收集器的情况下,promotion failed就是这种情况,这种原因经常由于并发收集器产生的碎片导致可用空间不足;concurrent mode failure是在执行CMS GC的过程中同时有对象要放入旧生代,而此时旧生代空间不足造成的。

      4. 永久代空间不足

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。

        5. System.gc

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

 

MixedGC 触发条件:

1. InitiatingHeapOccupancyPercent:堆占有率达到这个值则触发global concurrent marking,默认45%

2. G1HeapWastePercent:在global concurrent marking结束之后,可以知道区有多少空间要被回收,在每次YGC之后和再次发生Mixed GC之前,会检查垃圾占比是否达到了此参数,只有达到了,下次才会发生Mixed GC

需要同时满足以上两个条件可触发