JVM-动态年龄判断你真的理解了吗

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

看文章前,我们先复习一下。

什么对象才能直接进入老年代?

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

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

好了嘛,应该没了吧。

这次,我们把目光聚焦到:动态年龄判断。

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

image

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

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

简单点说:在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

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

你可能感兴趣的:(java程序员后端)