《深入理解Java虚拟机》中有如上的一段描述,讲的是动态对象年龄判定,避免-XX:MaxTenuringThreshold 设置过大导致大量对象无法晋升。
但是存在一个问题,如果说非得相同年龄所有对象大小总和大于Survivor空间的一半才能晋升,按照如下场景:
- MaxTenuringThreshold为15
- 年龄1的对象占用了33%
- 年龄2的对象占用33%
- 年龄3的对象占用34%。
得出推论:
- 按照晋升的标准。首先年龄不满足MaxTenuringThreshold,不会晋升。
- 每个年龄的对象都不满足50%,不会晋升。
Survivor都占用了100%了,但是对象就不晋升。导致老年代明明有空间,但是对象就停留在年轻代。但这个结论似乎与jvm的表现不符合,只要老年代有空间,最后还会晋升的。
把晋升年龄计算的代码摘出。我们来看看动态年龄的计算。
uint ageTable::compute_tenuring_threshold(size_t survivor_capacity) { //survivor_capacity是survivor空间的大小 size_t desired_survivor_size = (size_t)((((double) survivor_capacity)*TargetSurvivorRatio)/100); size_t total = 0; uint age = 1; while (age < table_size) { total += sizes[age];//sizes数组是每个年龄段对象大小 if (total > desired_survivor_size) break; age++; } uint result = age < MaxTenuringThreshold ? age : MaxTenuringThreshold; ... }
代码中有一个TargetSurvivorRatio的值。
# 目标存活率,默认为50% -XX:TargetSurvivorRatio
根据代码可以看到,动态年龄计算方式为:
- 通过这个比率来计算一个期望值,desired_survivor_size 。
- 然后用一个total计数器,累加每个年龄段对象大小的总和。
- 当total大于desired_survivor_size 停止。
- 然后用当前age和MaxTenuringThreshold 对比找出最小值作为结果。
总体表征就是,年龄从小到大进行累加,当加入某个年龄段后,累加和超过survivor区域*TargetSurvivorRatio的时候,就从这个年龄段网上的年龄的对象进行晋升。
动态对象年龄判断,主要是被TargetSurvivorRatio这个参数来控制。而且算的是年龄从小到大的累加和,而不是某个年龄段对象的大小。
参考:
《深入理解Java虚拟机》