JVM动态对象年龄判定

在深入理解Java虚拟机这本书里有这么一句话。

虚拟机并不是永远地要求对象的年龄必须达到了MaxTenuringThreshold才能晋升老年代,如果在Survivor空间中相同年龄所有对象大小的总和大于Survivor空间的一半,年龄大于或等于该年龄的对象就可以直接进入老年代,无须等到MaxTenuringThreshold中要求的年龄。

这句话的意思就是如果Survivor区中相同年龄的对象的大小超过了Survivor空间的一半,然后这个年龄再和我们设置的MaxTenuringThreshold(默认值15)晋升年龄阈值进行比较,两者取最小值,大于或等于此年龄的对象将会晋升到老年代。

但是呢,如果碰到下面这种情况,如果非得等到相同年龄对象的大小大于Survivor空间的一半才能晋升,就会导致Survivor空间被占满,但是无法晋升的问题。

  1. MaxTenuringThreshold设置为15
  2. 年龄1的对象占Survivor空间的33%
  3. 年龄2的对象占Survivor空间的33%
  4. 年龄3的对象占Survivor空间的34%
  1. 此时Survivor空间中的对象年龄最大的是3,不满足MaxTenuringThreshold,所以无法晋升到老年代。
  2. 每个年龄的对象占用都不超过50%,所以也无法晋升到老年代。但是实际上Survivor空间已经被占满。

但是实际上JVM碰到此种情况,还是会让一部分对象晋升到老年代。这个时候JVM又是怎么计算晋升对象的年龄?

-XX:TargetSurvivorRatio 目标存活率,默认为50%

  1. 通过这个比例来计算一个期望值,desired_survivor_size 。
  2. 然后用一个total计数器,累加每个年龄段对象大小的总和。
  3. 当total大于desired_survivor_size 停止。
  4. 然后用当前age和MaxTenuringThreshold 对比找出最小值作为结果。

总体JVM的表现就是年龄从小到大进行累加,当Survivor空间中新加入某个年龄段的对象时,累加超过Survivor区域大小*TargetSurvivorRatio的时候。大于或等于此年龄的对象将会晋升到老年代。下图刚好反映了此过程(-XX:+PrintTenuringDistribution输出对象年龄分布)

参考

  1. jvm误区-动态对象年龄判定
显示评论