共计 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
好了,说完了。有播种的话,记得点赞和转发哈哈哈。不然,打哭你 (霸气侧漏)