哈喽哈喽大家猴,我是把代码写成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
好了,说完了。有收获的话,记得点赞和转发哈哈哈。不然,打哭你(霸气侧漏)
作者:大头菜
链接:https://juejin.cn/post/6949829680753016863