java内存的分配策略

1.概述

本文是《深入理解java虚拟机》(周志明著)3.6节的笔记整理,文章结构也与书上相同,讲述的是几条最普遍的内存分配策略。

2.对象优先在Eden分配

** 大多数情况下,对象在新生代Eden去中分配,(注:java堆中的新生代可分为Eden区和两个Survivor区),当Eden区中没有足够的空间进行分配时,虚拟机将发起一次Minor GC。 **

Minor GC 和 Full GC的区别

  • 新生代GC(Minor GC):指的是发生在新生代中的垃圾收集动作,java对象的创建和回收非常频繁,所以Mnior GC非常频繁,一般回收速度也比较快。
  • 老年代GC(Major GC/Full FC):指发生在老年代中的GC,出现了Major GC经常会伴随至少一次的Minor GC(并非绝对),Major GC的速度一般会比Minor GC慢10倍以上。

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

大对象是指,需要大量连续内存空间的java对象(写程序的时候应该避免“短命大对象”),经常出现大对象,容易导致内存还有不少空间时,就提前触发垃圾收集以获取足够的连续空间来分给他们。
虚拟机提供-XX:PretenureSizeThreshold参数,令大于这个设置值的对象直接进入老年代,这么做为目的是为了避免在Eden以及两个Survivor区之间发生大量的内存复制(新生代的垃圾收集算法采用复制算法)。

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

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

5.动态对象的年龄判定

为了能更好的适应不同程序的内存状况,虚拟机不是永远地要求对象的年龄必须达到MaxTenuringThreshold才能晋升老年代,如果Survivor空间中相同年龄所有对象大小的总和大于Survivor空间的一半,年龄大于或者等于该年龄的对象就可以直接进入老年代。

6.空间分配担保

在发生Minor GC之前,虚拟机会先检查老年代中最大可用连续空间是否大于新生代所有对象总空间,如果这个条件成立,那么Minor GC可以确保是安全的。如果不成立,则虚拟机会查看HandlePromotionFailure设置值是否允许担保失败。如果允许,那么会继续检查老年代最大可用的连续空间是否大于历次晋升到老年代对象的平均大小,如果大于将尝试进行一次Minor GC。如果小于或者HandlePromotionFailure设置为不允许,那这时就改为一次Full GC。
分配担保解释:
新生代使用复制算法完成垃圾收集,为了节约内存Survivor的设置的比较小,当Minor GC后如果还有大量对象存活,超过了一个Survivor的内存空间,这时就需要老年代进行分配担保,把Survivor中无法容纳的对象直接进入老年代。若虚拟机检查老年代中最大可用连续空间大于新生代所有对象总空间那么就能保证不需要发生Full GC,因为老年代的内存空间够用。反之,如果老年代中最大可用连续空间小于新生代所有对象总空间就需要在尝试Minor GC失败后进行Full Gc或者直接Full GC。

猜你喜欢

转载自www.cnblogs.com/Mrfanl/p/10431966.html