1、对象优先在Eden区分配
大多数情况下,对象在新生代Eden区分配。当Eden区没有足够的空间进行分配时,虚拟机将发起一次Minor GC。
虚拟机提供了 -XX:+PrintGCDetails这个收集器参数,告诉虚拟机在发生垃圾回收时打印内存回收日志。并且在进程退出时输出当前的内存各区域分配情况。
2、大对象直接进入老年代
所谓的大对象是指需要大量连续内存空间的Java对象。大对象对虚拟机的内存分配来说是一个坏消息,经常出现大对象导致内存还有不少空间时就提前触发垃圾回收以获得足够的连续空间来“安置”大对象。
虚拟机提供了一个-XX:pretenureSizeThreshold参数,令大于这个设置值的对象直接在老年代分配,这样做的目的是避免在Eden及两个Survivor区域间发生大量的内存复制。
3、长期存活的对象将直接进入老年代
虚拟机采用分代收集的思想管理内存,则内存回收即必须识别哪些对象应该放在老年代,哪些对象应该放在新生代。为了做到此,虚拟机给每个对象设置了年龄计数器(Age)。
如果对象在Eden区域出生并且经过一次Minor GC后依然存活,并且被Survivor区域容纳话没,被移至Survivor区域,年龄+1。对象在Survivor区域每“熬过”一次Minor GC,年龄就+1,当其年龄增加到一定程度(默认15),就会晋升至老年代。
对象晋升老年代的年龄阈值,可以通过-XX:MaxTenuringThreshold参数设置。
4、动态对象年龄判定
为了更好的适应不同程序的内存状况,虚拟机并不是永远的要求对象的年龄必须达到MaxTenuringThreshold才能晋升老年代,如果在Survivor空间中相同年龄所有对象大小总和大于Survivor空间的一半,年龄大于或等于该年龄的对象可以直接进入老年代,无需等到MaxTenuringThreshold中要求的年龄。
5、空间分配担保
在发生Minor GC之前,虚拟机会先检查老年代的最大可用的连续空间是否大于新生代所有对象的总空间,如果条件成立,那么Minor GC可以确保是安全的。如果不成立,则虚拟机会查看HandlePromotionFailure设置的值是否允许担保失败。如果允许,那么会继续检查老年代最大可用的连续空间是否大于历次晋升老年代对象的平均大小,如果大于,将尝试进行一次Minor GC,尽管这次Minor GC是有风险的;如果小于,或者HandlePromotionFailure设置不允许冒险,那么这时要改为进行一次Full GC。