前提条件
Eden区的空间最大只能容纳10个对象
Survivor区总容量为8,S0和S1各自容量为4
每个对象大小相等且小于-XX:PretenureSizeThreshold设置的值
动态年龄判断的参数-XX:TargetSurvivorRatio为默认值,50%
具体步骤
Eden区空间不足,触发第一次Minor GC,存活的对象复制到S0区。将对象移动到S0区后,清空Eden区。
Eden区空间不足,触发第二次Minor GC后,Eden区有两个存活的新对象,S0区有两个存活的对象,此时S1区刚好可以容纳4个对象,所以直接将存活的对象复制到S1区。
Eden区空间不足,触发第三次Minor GC后,Eden区有1个存活的新对象,S1区有3个存活的对象,此时S0区刚好可以容纳4个对象,所以将Eden区和S1区存活的对象复制到S0区。
Eden区空间不足,触发第四次Minor GC后,Eden区有2个存活的新对象,但是此时Eden区加S1区的存活对象所占用的空间大于Survivor区的一半,需要计算出可以进入老年代的对象,目前各年龄段的对象情况为:1岁2个,2岁1个,3岁1个,4岁2个,2+1+1=41-3岁的对象所占用的空间刚好为Survivor区的一半,故大于3岁的对象进入老年代。(如果年龄为2的对象有3个的话,大于等于2岁的对象都会进入老年代)
小结
可进入老年代的对象年龄默认为15,该值可由 -XX:maxTenuringThreshold 属性设置,但是当年轻代的对象占用空间大于Survivor空间的一半时,会根据动态年龄判断算法计算出可以进入老年代的对象,并不是必须达到设定的年龄值才会进入老年代。
当新建的对象大于-XX:PretenureSizeThreshold设置的值时,该对象会直接进入老年代。
日常开发中应该注意频繁创建对象的地方,避免再循环体内新建对象,Android项目避免再onDraw方法中创建对象,因为频繁地创建临时对象会频繁地触发GC,从而导致内存抖动的产生,影响程序性能。
参考
JVM-动态年龄判断你真的理解了吗
关于JVM中Eden区、Survivor from区和Survivor to区的理解