一.内存分配策略
1.对象优先在Eden分配.
大多数情况下,对象在新生代Eden区分配,当Eden区空间不够时,发起Minor GC.
2.大对象直接进入老年代
大对象是指需要连续内存空间的对象,最典型的大对象是那种很长的字符串以及数组.经常出现大对象的话会提前触发垃圾收集以获取足够的连续空间分配给大对象.
-XX:PretenureSizeThreshold,大于此值的对象直接在老年代分配,避免在Eden区和Survivor区之间的大量内存复制.
3.长期存活的对象进入老年代
为对象定义年龄计数器,对象在出生并经过Minor GC依然存活,将移动到Survivor区,年龄就增加一岁,增加到一定年龄时移动到老年代中.
-XX:MaxTenuringThreshold用来定义年龄的阈值
4.动态对象年龄判定
虚拟机并不是永远的要求对象的年龄必须达到MaxTenuringThreshold才能晋升老年代,如果在Survivor中相同年龄所有对象大小的总和大于Survivor空间的一半,则年龄大于或等于该年龄的对象可以直接进入老年代,而无需等到MaxTenuringThreshold中要求的年龄.
5.空间分配担保
在发生Minor GC之前,虚拟机先检查老年代最大可用的连续空间是否大于新生代所有对象总空间,如果大于,则Minor GC是安全的.
如果不大于,虚拟机先查看HandlePromotionFailure设置值是否允许担保失败,如果允许那么就会继续检查老年代的最大可用连续空间大小是否大于历次晋升到老年代对象的平均大小,如果大于,将尝试进行一次Minor GC,如果小于,或者HandlePromotionFailure设置为不允许冒险,那么就进行一次Full GC.
Full GC的触发条件
对于Minor GC,其触发条件非常简单,当Eden区满的时候就将触发一次Minor GC,而Full GC则相对复杂,有以下条件:
1.调用System.gc()
只是建议虚拟机执行Full GC,但是虚拟机不一定真正去执行,不建议使用这种方式,而是让虚拟机管理内存.
2.老年代空间不足
老年代空间不足的常见场景为前文所讲的大对象直接进入老年代,长期存活的对象进入老年代等.
为了避免以上原因引起的Full GC,应当尽量不要创建过大的对象以及数组.除此之外,还可以通过**-Xmn虚拟机参数调大新生代的大小,让对象尽量在新生代被回收掉,不进入老年代.还可以通过-XX:MaxTenuringThreshold**调大对象进入老年代的年龄,让对象在新生代多存活一段时间.
3.空间分配担保失败
使用复制算法的Minor GC需要老年代的内存空间作担保,如果担保失败会执行一次Full GC.
4.Concurrent Mode Failure
执行CMS GC的过程中同时有对象要放入老年代,而此时老年代空间不足(可能是GC过程中浮动垃圾过多而导致暂时性的空间不足),便会报Concurrent Mode Failure错误,并触发Full GC.