「这是我参与11月更文挑战的第5天,活动详情查看:2021最后一次更文挑战」
内存分配
大部分的对象在新生代Eden区中分配。当Eden区没有足够的空间时,虚拟机会发起一次Minor GC。
大对象直接进入老年代。大对象:需要大量连续内存空间的对象,如超长字符串、超多元素的数组等。
HotSpot提供了-XX:PretenureSizeThreshold【-XX:PretenureSizeThreshold=1024】参数来声明对象占用内存大于设定值时,直接在老年代中分配。
虚拟机给每个对象定义了一个年龄计数器,存储在对象头中。对象在新生代分配内存后,经过第一次Minor GC后存活,并进入幸存区(Survivor)后,这个对象的年龄为1岁。对象在survivor区中每经过一次Minor GC,年龄就增1岁。当年龄到15岁时(默认为15,年龄阈值可通过【-XX:MaxTenuringThreshold】进行设置),对象会进入老年代。
并不是只有年龄超过阈值的对象才能进入老年代,如果survivor区中的相同年龄的对象占用的内存总和大于survivor空间的一半,那么大于等于这个年龄的对象都会进入老年代。
空间分配担保
发生Minor GC之前,虚拟机必须检查老年代最大可用的连续空间是否大于新生代中所有对象的总空间。
-
如果大于,那么可以确保是安全的Minor GC
-
如果小于,虚拟机会去判断是否允许担保失败,通过【-XX:HandlePromotionFailure】参数的设置来判断。
-
允许担保失败,继续检查老年代最大可用的连续空间大小是否大于历史分配在老年代对象的平均大小。
- 大于,尝试进行一次Minor GC(存在风险)。
- 小于,进行Full GC。
-
不允许担保失败,进行Full GC。
-
如下图所示:
但在JDK 6 Update24之后规则就发生了改变,【-XX:HandlePromotionFailure】参数不再生效,只要老年代最大可用的连续空间大小大于新生代对象总大小或历史进入老年代对象的平均大小,就会直接Minor GC,否则进行Full GC。