美文网首页
垃圾收集器知识点总结-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