内存分配与回收策略

整理自《深入理解 Java 虚拟机》。

对象的内存分配,大方向上讲,就是在堆上分配,对象主要分配在新生代的 Eden 区上,如果启动了本地线程分配缓冲,将按线程优先在 TLAB 上分配。少数情况下也可能会直接分配在老年代中,分配规则并不是百分百固定,其细节取决于当前使用的是哪一种垃圾收集器组合,还有虚拟机中与内存相关的参数的设置。以下是在使用 Serial+Serial Old 收集器下的内存分配和回收策略。

1. 对象优先在Eden分配

大多数情况下,对象在新生代 Eden 区中分配。当 Eden 区没有足够的空间进行分配时,虚拟机将发起一次 Minior GC。如果 GC 期间虚拟机发现已有的对象无法放入 Survivor 空间,那么通过分配担保机制提前转移到老年代去。

2. 大对象直接进入老年代

需要大量连续内存空间的 Java 对象称为大对象,大对象的出现会导致还有不少内存空间时就提前触发垃圾收集以获取更大的连续的空间来进行大对象的分配。虚拟机提供了 -XX:PretenureSizeThreadshold 参数来设置大对象的阈值,超过阈值的对象直接分配到老年代。

3. 长期存活的对象将进入老年代

虚拟机给每个对象定义了一个对象年龄(Age)计数器。如果对象在 Eden 出生并经过第一次Minor GC 后仍然存活,并且能被 Survivor 容纳的话,将被移动到Survivor空间中,并且对象年龄设为1,对象在 Survivor 区每次经过一次 Minor GC,年龄就加1,当它的年龄增加到一定程度(默认为15岁),就将会被晋升到老年代中。对象晋升老年代的年龄阈值,可以通过参数-XX:MaxTenuringThreshold设置。

4. 动态对象年龄判定

对象的年龄到达了 MaxTenuringThreshold 可以进入老年代,同时,如果在 survivor 区中相同年龄所有对象大小的总和大于 Survivor 区的一半,年龄大于等于该年龄的对象就可以直接进入老年代。无须等到 MaxTenuringThreshold 中要求的年龄。

5. 空间分配担保

如果经过一次 Minor GC 后有大量对象存活,而新生代的 Survivor 区很小,放不下这些大量存活的对象,所以需要老年代进行分配担保,把 Survivor 区无法容纳的对象直接进入老年代。 在发生 Minor GC之前,虚拟机会先检查老年代最大可用的连续空间是否大于新生代所有对象总空间,如果这个条件成立,那么 Minor GC 可以确保是安全的。JDK6 Update 24 之后的规则为只要老年代的连续空间大于新生代对象总大小或者历次晋升的平均大小就会进行 Minor GC,否则将进行 Full GC。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值