对象的内存分配,大方向讲,就是在堆上分配(但也可能经过JIT(及时编译器)编译后被拆散为标量类型并间接地分配在栈上),对象主要分配在新生代的Eden上,如果启动了本地线程分配缓冲,将按线程优先在TLAB( Thread Local Allocation Buffer,即线程本地分配缓存区 )上分配。少数情况下也可能直接分配在老年代中。
分配的规则并不是固定的。
1.对象优先分配在Eden
大多数情况下,对象在新生代Eden区中分配。当Eden没有足够空间时,虚拟机会发起一次MinorGC。
2.大对象直接进入老年代
所谓大对象,是指需要大量连续内存空间的Java对象,例如,很长的字符串以及数组。大对象对虚拟机大的内分配来说是一个坏消息,但更糟的是一群“朝生夕灭”的“短命”大对象。经常出现大对象容易导致内存还有不少空间时提前触发GC,以获取足够的连续空间来分配给它们。
3.长期存活的对象进入老年代
为了识别哪些对象应该放在新生代,哪些应该放在老年代,虚拟机给每个对象定义了一个对象年龄(Age)计数器。如果对象在Eden出生并经过第一次MinorGC后仍然存活,并能别Survivor容纳,将被移动到Survivor区中,并且Age设为1。
对象在Survivor中每经过一次MinorGC,并存活,就将Age加1,当Age计数器达到一定值(默认为15)时,对象就会进入老年代。
4.动态对象年龄判定
虚拟机并不是永远要求对象年龄达到某定值才能进入老年代,如若Survivor空间中相同年龄所有对象大小的总合大于Survivor空间的一半,年龄大于或等于该年龄的对象就可以直接进入老年代。
5.空间分配担保
MinorGC发生之前,虚拟机会检查老年代最大可用的连续空间是否大于新生代所有对象总空间。
- jdk6u24之前:虚拟机会查看HanldlePromotionFailure设置值是否允许担保失败。如果允许,会继续检查老年代最大可用空间是否大于历次晋升老年代对象的平均水平。如果大于,将尝试着进行MinorGC;如果小于,或者HanldlePromotionFailure设置 为不允许冒险,将改为FullGC
- jdk6u24之后:如果年代最大可用空间是否大于历次晋升老年代对象的平均水平 ,进行MinorGC;否则进行FullGC