参考《深入理解java虚拟机》一书,以下均为在HotSpot虚拟机,Serial与Serial Old垃圾收集器中的情况。
1.对象优先分配在Eden区、长期存活的对象将进入老年代
在创建对象时,正常情况下对象会分配在堆中的Eden区(新生代)。在持续分配新对象至Eden区直至Eden区内存不足以分配新的对象时,即会触发Minor GC回收Eden区,正常情况下Eden区的对象大多朝生夕死(生命周期很短)GC时大部分都会被回收,剩余未被回收的对象则会进入Survivor区(幸存者区),每次Minor GC后幸存下来的对象年龄(存放在对象头中)都会加一,当该年龄超过虚拟机默认15岁(可通过-XX:MaxTenuringThreshold配置)后则会被移动到老年代中。
2.大对象直接进入老年代
用户可通过配置-XX:PretenureSizeThreshold参数指定大于你所指定大小以上的对象不经过正常年龄增长流程直接分配在老年代中,例-XX:PretenureSizeThreshold=3145728,即指定3MB大小以上的对象直接分配在老年代。
注:在开发时应避免大对象的产生,它会导致在还有不少空间但没有足够的连续空间用于存放该大对象时就会触发GC,从而降低系统吞吐量,并且大对象在复制阶段意味着更高的开销。
3.动态对象年龄判断
第一条中对象通过年龄的增长可以从新生代晋升到老年代,这只是晋升的方法之一,还有另一种方法,即动态对象年龄判断。
动态对象年龄判断,即在survivor区中低于或等于某年龄的的所有对象大小的总和大于Survivor空间的一半时,大于或等于改年龄的对象就可以直接进入老年代,无需等到-XX:MaxTenuringThreshold中要求的年龄该部分引用自《深入理解java虚拟机》P134原话。
例如:当在Minor GC发生时,年龄小于等于5岁的对象大小总和超过了survivor区总内存的一半,那么年龄大于等于5岁的对象即可以直接进入老年代。
4.空间分配担保
JDK6 Update24 前:
1.虚拟机检查老年代连续空间是否大于新生代所有对象总空间。
2.在第一条不成立的情况下,虚拟机会先查看-XX:HandlePromotionFailure参数是否允许担保失败,不允许时会直接进行Full GC。
3.在第二条参数为允许的情况下,虚拟机会继续检查老年代最大可用连续空间是否大于历次晋升到老年代对象的平均大小。
4.第三条若为大于,则可尝试进行一次有风险的Minor GC(若这次新生代晋升的对象突增,远高于历次晋升的对象总和大小,则会担保失败,转而进行一次Full GC);若第三条为小于则会进行一次Full GC。
JDK6 Update24 后:
不在受到-XX:HandlePromotionFailure配置的影响。
只要老年代连续空间大于新生代对象总大小或者历次晋升的平均大小,就会进行Minor GC,否者进行Full GC。