一、对象优先在 Eden 分配
大多数情况下,对象在新生代 Eden 中分配。当 Eden 区空间不足以分配时,虚拟就将发起一次 Minor GC。
二、大对象直接进老年代
大对象指需要大量连续内存空间的 Java 对象,最典型的大对象就是那种很长的字符串,或者元素数量很庞大的数组。
HotSpot 提供了 -XX:pretenureSizeThreshoid
参数,指定大于该设置值的对象直接在老年代分配,这样做的目的就是避免在 Eden 区及两个 Survivor 区之间来回复制,产生大量的内存复制操作。
-XX:pretenureSizeThreshoid
参数只对 Serial 和ParNew 两款收集器有效。
三、长期存活对象进老年代
虚拟机给每个对象定义了一个对象年龄计数器,存在在对象头中。对象在 Survivor 区中每熬过一次 Minor GC,年龄就增加 1 随,当它的年龄增加到一定程度(默认15),就会被晋升到老年代中。
对象晋升老年代的年龄阈值,可以通过参数 -XX:MaxTenuringThreshold
设置。
四、动态对象年龄判定
为了能更好地适应不同程序的内存状况, HotSpot 并不是永远要求对象的年龄必须达到 -XX:MaxTenuringThreshold
才能晋升老年代,如果在 Survivor 空间中相同年龄所有对象大小的总和大于 Survivor 空间的一半,年龄大于或等于该年龄的对象就可以直接进入老年代,无须等到 -XX:MaxTenuringThreshold
中要求的年龄。
五、空间分配担保
在发生 Minor GC 之前,虚拟机必须先检查老年代最大可用的连续空间是否大于新生代所有对象总空间,如果这个条件成立,那这一次 Minor GC 可以确保是安全的。
如果不成立,虚拟机会先查看 -XX::HandlePromotionFailure
参数的设置值是否允许担保失败;如果允许,那会继续检查老年代最大可用的连续空间是否大于历次晋升到老年代对象的平均大小,如果大于,将尝试进行一次 Minor GC,尽管这次 Minor GC 是有风险的;如果小于,或者 -XX::HandlePromotionFailure
设置不允许冒险,那这是就要改成进行一次 Full GC。
在 JDK 6 Update 24 之后,-XX::HandlePromotionFailure
不再影响到虚拟机的空间分配担保策略。规则变为:只要老年代的连续空间大于新生代对象总大小或者历次晋升的平均大小,就会进行 Minor GC,否则将进行 Full GC。