美文网首页
垃圾收集器知识点总结-MaxTenuringThreshold

垃圾收集器知识点总结-MaxTenuringThreshold

作者: _六道木 | 来源:发表于2018-12-08 16:45 被阅读15次

MaxTenuringThreshold该参数用于控制对象经过GC多少次仍然存活后晋升到老年代的最大阈值,参数最大可配置为15,即对象最多经过15次GC后仍然存活就会晋升到老年代

记住!是最大!也就是说实际上不一定会经过15次才能晋升!这个值的JVM内部会进行动态计算然后动态改变的。

最近在线上有个应用GC非常频繁,MaxTenuringThreshold参数配置的是15,而以前对这个参数的理解是一定要经过15次后才会晋升,所以导致整个排查过程根本就不对,线上日志如下:

Desired survivor size 184549376 bytes, new threshold 1 (max 15)
- age   1:        369096960 bytes,        369096960 total
....下面进行GC,年轻代有很多对象全跑到了老年代

当时思考方向是:age为1,离15有很大的距离,不应该会晋升,老年代空间增加是因为大对象

这个思考方向真是大错特错了,因为对MaxTenuringThreshold理解错了。注意日志中有几个关键字

new threshold 1 (max 15)

意思是说阈值现在变成了1,而不是15!所以直接就晋升了!那么为什么会变成1呢,这个动态计算的算法是怎么样的,参考了一下一些大神的文章再看了下源码,终于发现原因所在,直接看源码会比较清晰,源码如下:

int ageTable::compute_tenuring_threshold(size_t survivor_capacity) {
  //TargetSurvivorRatio默认为50
  //desired_survivor_size = survivor的空间*50%
  size_t desired_survivor_size = (size_t)((((double) survivor_capacity)*TargetSurvivorRatio)/100);
  size_t total = 0;
  int age = 1;
  assert(sizes[0] == 0, "no objects with age zero should be recorded");
  while (age < table_size) {
    // 循环遍历所有年龄代的对象累加得到一个大小
    total += sizes[age];
    // 如果该大小大于desired_survivor_size,即survivor的空间*50%,那么退出循环
    if (total > desired_survivor_size) break;
    age++;
  }
  // 如果算出来的age大于MaxTenuringThreshold则使用MaxTenuringThreshold,否则使用计算出来的age
  int result = age < MaxTenuringThreshold ? age : MaxTenuringThreshold;

  if (PrintTenuringDistribution || UsePerfData) {
    if (PrintTenuringDistribution) {
      gclog_or_tty->cr();
      // 这里就是线上出现的那个日志所在的地方
      gclog_or_tty->print_cr("Desired survivor size %ld bytes, new threshold %d (max %d)",
        desired_survivor_size*oopSize, result, MaxTenuringThreshold);
    }
  //....
  }
  // 返回计算的年龄
  return result;
}

经过多次GC,存活的对象会在From和To两个地方来回的存放,而前提是两个空间能有足够的大小去存放这些数据,上述算法中,会计算每个年龄的大小,如果达到某个年龄后发现总大小以及大于Survivor的大小的50%,那么这时候就需要调整阈值,不能继续等到15次GC后才晋升,这样会导致Survivor的空间不足,所以调整阈值,让其尽快晋升

回到线上的那个例子,线上我记得是没配置TargetSurvivorRatio属性,那么按照50%算,survivor * 50%=184549376,在while循环中计算第一个年龄代=369096960>184549376,那么退出循环,此时计算得到的年龄为1,所以这个年龄的对象会提前晋升

参考文章:
https://www.jianshu.com/p/f91fde4628a5
https://blog.csdn.net/FoolishAndStupid/article/details/77596050?fps=1&locationNum=1

相关文章

网友评论

      本文标题:垃圾收集器知识点总结-MaxTenuringThreshold

      本文链接:https://www.haomeiwen.com/subject/nebqhqtx.html