关于java:JVM动态年龄判断你真的理解了吗

48次阅读

共计 2045 个字符,预计需要花费 6 分钟才能阅读完成。

哈喽哈喽大家猴,我是把代码写成 bug 的大头菜。公众号:大头菜技术 (bigheadit)。原创不易,但欢送转载。

看文章前,咱们先温习一下。

什么对象能力间接进入老年代?

你可能很快就说进去,毕竟八股文不是白背的。

  • 大对象间接进入老年代。
  • 动静年龄判断
  • 年龄大于阈值,进入老年代
  • Minor GC 后,存活的对象空间大于 survivor 空间,间接进入老年代。

好了嘛,应该没了吧。

这次,咱们把眼光聚焦到:动静年龄判断。

上面这图片,摘自 JVM 书的一段话:

什么时候对象能进入老年代空间时?

其中一个触发条件就是:动静年龄判断。

简略点说:在 survivor 中,雷同年龄的所有对象大小大于 survivor 的个别空间。年龄大于或等于该年龄的对象能够进入老年代。

但真的是这样子吗?

前提条件:当初我假如 survivor 空间有 100M 空间。

来。我举个例子哈,跟着我的思路走一遍。

假如年龄 3 的对象大小超过了 survivor 区域的一半,比方占据 60M 吧。

咱们剖析一下:年龄为 3,阐明经验了 3 次 GC 都存活了下来。

而后咱们思考一下, 年龄 3 的对象是从哪里来的?

必定是从年龄 2 的对象中来的。这点毋庸置疑吧!

咱们再换个思路想一下。

既然,年龄 3 的对象是从年龄 2 的对象中来的。(先阐明哈:年龄,只增不减)

当初年龄 3 的对象都曾经超过 survivor 区域的一半了。

那是不是能够阐明: 年龄 2 的对象也必定超过 survivor 区域的一半。

同理可得:年龄 2 的对象是从年龄 1 的对象中来的,那么年龄 1 的对象也必定超过一半,是吧。这毋庸置疑吧!

咱们来温习一下:

在 survivor 中,雷同年龄的所有对象大小大于 survivor 的个别空间。年龄大于或等于该年龄的对象能够进入老年代。

你看,如果真的是如下面所说的规定。超过一半空间,该年龄或大于该年龄的对象,都进入老年代。

那还有年龄 3 的对象什么事呢?

因为年龄 3 的对象,是从年龄 2 对象来的,而年龄 2 对象是从年龄 1 中的对象来的。

进入老年代的应该在年龄 1 的对象。压根不会不倒退到年龄 3 的对象。

但真的是这样子吗?

必定不是,让超过 survivor 区域个别的年龄 1 的对象间接进入老年代。JVM 的设计者疯了吗?

还是书本的形容有错呢?

真实情况是这样子的:

年龄 1 + 年龄 2 + 年龄 3 + 年龄 N 的对象加起来的空间,大于 survivor 区域的一半,就会让年龄 N 和年龄 N 以上的对象进入老年代。动静年龄判断应该是这样子的。说的艰深一点:就是年龄从小到大对象的占据空间的累加和,而不是某一个特定年龄对象占据的空间。

有没有被书本骗了的感觉。。。。

好嘛,如果你还不信。

Talk is cheap,Show me the money

搞错了,重来

Talk is cheap ,Show me the code。

uint ageTable::compute_tenuring_threshold(size_t survivor_capacity) {
    //survivor_capacity 是 survivor 空间的大小
  //desired_survivor_size 就是动静年龄判断是否对象进入老年代的阈值
  //TargetSurvivorRatio:默认 50
  size_t desired_survivor_size = (size_t)((((double) survivor_capacity)*TargetSurvivorRatio)/100);
  size_t total = 0;
  uint age = 1;
  while (age < table_size) {
  //sizes 数组是每个年龄段对象大小
  //total 就是年龄从小到大的对象占据的空间累加和
    total += sizes[age];
  // 如果累加和大于阈值,就间接跳出循环,假如磁盘的 age 等于 3 吧
    if (total > desired_survivor_size) break;
    age++;
  }
  //MaxTenuringThreshold 下限是 15,当初 age 是 3,那么 result 就是等于 3
  uint result = age < MaxTenuringThreshold ? age : MaxTenuringThreshold;
    ...
}

下面这段代码,也证实了我的猜测:

真正的动静年龄判断:是年龄从小到大的对象占据的空间,大于 survivor 区域的一半,而后把等于或大于该年龄的对象,放入到老年代。

小结

这就是书本理实践和实际的差距吧。你不真正看一下源码,可能始终都认为书本说的是真的。这也从侧面阐明了:源码无机密。

补充常识

  • 大对象间接进入老年代。

    • 那多大的对象是大对象?大于上面参数的对象,就是大对象
    • 间接通过:-XX:PretenureSizeThreshold 来配置
  • 动静年龄判断

    • 外面波及到一个值,就是 survivor 区域的一半,其实也不肯定是一半,你能够自定义的
    • 参数:-XX:TargetSurvivorRatio
  • 年龄大于阈值,进入老年代

    • 这个阈值:JDK8 后,范畴是 1 -15
    • 参数:XX:MaxTenuringThreshold

好了,说完了。有播种的话,记得点赞和转发哈哈哈。不然,打哭你 (霸气侧漏)

正文完
 0