JVM内存分配策略:
1 对象优先在Eden中分配
在大多数情况下,对象在新生代Eden中分配,当Eden区没有足够空间进行分配的时候,JVM会发起一次Minor GC.。
2 大对象直接进去老年代
所谓大对象是指,需要大量连续内存空间的Java对象。最典型的大对象是那种很长的字符串以及数组。大对象对应JVM的内存分配来说是一个坏消息(跟坏的消息:遇到一群"朝生夕灭"的"短命大对象"),经常出现大对象容易导致内存还有不少空间,但是因为没有足够的连续空间而导致提前触发垃圾回收来安置它们。
JVM提供了一个 -XX:PretenureSizeThreshold 参数。作用:大于这个值的对象直接在老年代分配,避免大对象在Eden和两个Survivor之间发生大量的内存复制。
3 长期存活的对象将进入老年代
JVM给每个对象设置了一个对象年龄(Age)计数器,每熬过一场Minor GC之后,对象年龄增加1岁,当它的年龄增加到阈值(默认为15),就会晋升到老年代。
JVM提供了一个 -XX:MaxTenuringThreshold 参数。作用:设置对象晋升老年代的年龄阈值。
4 动态年龄判定
为了适应不同程序的内存状态,JVM并不是永远要求对象的年龄必须达到MaxTenuringThreshold之后才能晋升老年代。
动态条件 : 如果在Survivor空间中的相同年龄的所有对象大小的总和大于Survivor空间的一半,年龄大于或等于该年的对象就可以直接进入老年代,无需等到指定的阀值
PS:假设Survivor的空间大小为max,年龄为y的对象总共有n个,如果y*n > max/2,那么所有年龄大于y或者等于y的对象全部进入到老年代。
5 Minor GC(JDK 1.6 Update 24之后)
JVM在进行一次Minor GC之前,只要老年代的连续空间大于新生代对象总大小或者历次晋升的平均大小就会进行Minor GC,否则进行FullGC。
PS:在1.6之前,有这个HandlePromotionFailure参数,代表是否要冒险进行一次Minor GC,如果是true,则再走上面的流程。如果是false,则进行Full GC。1.6之后不在使用此参数。