深入理解Java虚拟机:JVM高级特性与最佳实践(三):内存分配与回收策略

java技术体系中所提倡的内存管理最终可以归为自动化的解决了两个问题:给对象分配内存已经回收分配给对象的内存。

对象优先在Eden分配

 大多数情况下,对象在新生代Eden区中分配,当eden 区没有足够的空间进行分配时,虚拟机将发起一次Minor GC。 虚拟机提供了-XX:+PrintGCDetails 这个收集器日志参数,告诉虚拟机在发生垃圾收集行为时打印内存回收日志,并且在进程退出的时候输出当前内存各区域的分配情况。

大对象直接进入年老代

所谓大对象就是指,需要大量连续内存空间的java 对象。最典型的大对象就是那种很长的字符串极数组。虚拟机提供了一个-xx:pretenureSizeTreshold 参数,令大于这个设置值的对象直接在老年代中分配。这样做的目的是避免在Eden 区及两个Survivor区之间发生大量的内存拷贝。(复习一下新生代采用的是复制算法)

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

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


总结

 年轻代(Young Generation):对象被创建时,内存的分配首先发生在年轻代(大对象可以直接被创建在年老代),大部分的对象在创建后很快就不再使用,因此很快变得不可达,于是被年轻代的GC机制清理掉(IBM的研究表明,98%的对象都是很快消亡的),这个GC机制被称为Minor GC或叫Young GC。注意,Minor GC并不代表年轻代内存不足,它事实上只表示在Eden区上的GC。


 老年代:

  老年代存储的对象比年轻代多得多,而且不乏大对象,对老年代进行内存清理时,如果使用停止-复制算法,则相当低效。一般,老年代用的算法是标记-整理算法,即:标记出仍然存活的对象(存在引用的),将所有存活的对象向一端移动,以保证内存的连续。

     在发生Minor GC时,虚拟机会检查每次晋升进入老年代的大小是否大于老年代的剩余空间大小,如果大于,则直接触发一次Full GC,否则,就查看是否设置了-XX:+HandlePromotionFailure(允许担保失败),如果允许,则只会进行MinorGC,此时可以容忍内存分配失败;如果不允许,则仍然进行Full GC(这代表着如果设置-XX:+Handle PromotionFailure,则触发MinorGC就会同时触发Full GC,哪怕老年代还有很多内存,所以,最好不要这样做)。


你可能感兴趣的:(深入理解Java虚拟机:JVM高级特性与最佳实践(三):内存分配与回收策略)