在Java虚拟机中,内存分配与回收策略是一项至关重要的技术细节。这一策略关乎对象的生命周期以及内存的有效利用。

大部分对象会在新生代Eden区中进行分配。当Eden区没有足够的空间进行分配时,会触发Minor GC。这一过程可以通过参数-XX:+PrintGCDetails进行详细的日志记录,以便了解内存回收的详细情况。而参数-XX:SurvivorRatio=8则决定了新生代中Eden区与一个Survivor区的空间比例。
当谈及新生代GC(Minor GC)时,由于Java对象大多具有朝生夕灭的特性,这种GC行动非常频繁,但通常回收速度也很快。另一方面,老年代GC(Major GC或Full GC)则发生在老年代,其速度一般会比Minor GC慢很多,通常是慢十倍以上。
对于大对象,那些需要大量连续内存空间的Java对象,会直接进入老年代。这一策略通过参数-XX:PretenureSizeThreshold进行设置,目的是为了避免在新生代发生大量的内存复制。这一设置只对Serial和ParNew两款收集器有效。
为了区分哪些对象应放在新生代,哪些应放在老年代,虚拟机为每个对象定义了一个对象年龄计数器。对象在Eden出生并经过第一次Minor GC后,如果仍然存活且能被Survivor容纳,就会被移动到Survivor空间,并开始计算年龄。当对象的年龄增加到一定程度(默认为15岁)时,就会被晋升到老年代。但虚拟机的动态对象年龄判断机制并非严格要求对象必须达到MaxTenuringThreshold才能晋升老年代。如果在Survivor空间中相同年龄所有对象的大小总和大于Survivor空间的一半,那么年龄大于或等于该年龄的对象就可以直接进入老年代。
我们谈谈空间分配担保。在发生Minor GC之前,虚拟机会检查老年代的最大可用连续空间是否大于新生代所有对象的总空间。如果条件成立,那么Minor GC可以被认为是安全的。如果不成立,那么会根据HandlePromotionFailure的设置值来决定是进行一次有风险的Minor GC还是转为Full GC。新生代使用复制收集算法,为了内存利用率,只使用一个Survivor空间作为轮换备份。当出现大量对象在Minor GC后仍然存活的情况,就需要进行分配担保,把无法容纳在Survivor空间的对象直接进入老年代。但前提是老年代还有足够的空间来容纳这些对象。在JDK1.6之后的版本中,只要老年代的连续空间大于新生代对象总大小或历次晋升的平均大小,就会进行Minor GC,否则将进行Full GC。HandlePromotionFailure参数不再影响虚拟机的空间分配担保策略。
以上就是关于Java虚拟机内存分配与回收策略的详细解析。
文章来自《钓虾网小编|www.jnqjk.cn》整理于网络,文章内容不代表本站立场,转载请注明出处。