堆内存模型:
年轻代:
根据分代算法,默认小于15岁的对象称作年轻代,年轻代分为Eden区、幸存者区(Survivor Form,Survivor To),三者比例为:8:1:1
Eden 分区:对象出生分区,新对象存放区域
幸存者分区:经过一次MinorGC后依然存活的对象会移动到此。
老年代:
根据分代算法默认大于15岁的对象称作老年代对象,JVM会将年轻代对象移动至老年代。
永久代:
永久保存数据区域。主要保存Class等元数据信息,JDK1.8开始移除永久代用Metadata元数据区来存放,将永久代从堆中直接放置到直接内存中。原因本人觉得,是由于目前以Spring为主流的的动态代理、反射的大量使用,导致永久代的空间需求和用途已经发生非常大的改变,移除到直接内存中,可以简化JVM垃圾回收,内存管理的工作,也扩展了永久代的占用空间,操作使用更加的便捷。
jvm堆模型默认配置参数:
★ Eden:From:To - > 8:1:1
★ 年轻代:老年代 - > 1 : 2
分代算法:
JVM为每个对象建立一个年龄计数器,每执行一次MinorGC仍然存活的对象,则计数器加1,位于Eden分区的对象,会被移动到幸存者分区(Survivor),默认满15岁会被晋升为老年代。
分配策略
1.对象优先在Eden分配
新建对象一般会存放于Eden分区。如果Eden分区空间不足,则执行MinorGC,进行垃圾回收,如果依然无法存放,将放置到Survivor分区,如果Survivor分区依然空间不足,则会将Survivor分区的对象通过分配担保机制提前转移到老年代。
2.大对象直接进入老年代
新建对象需要大量连续内存空间,超过 JVM指定阀值(-XX:PretenureSizeThreshold)时,对象将直接在老年代中分配。
3.长期存活的对象将进入老年代
内存中对象的年龄超过JVM通过指定阀值(-XX:MaxTenuringThreshold=15)后,将直接进入老年代
4.动态对象年龄判定
Survivor分区中,相同年龄所有对象大小的总和大于Survivor分区大小的一般是,自动进入老年代。
5.空间分配担保
如果多次MinorGC后,Survivor分区依然没有空间存放对象,则在老年代空间足够的情况下直接转为老年代。
- 如果数据大小大于老年代数据空间,则担保分配失败
- 如果数据大小大于晋升为老年代的数据平均大小,则担保分配失败。
- 如果数据大小大于参数HandlePromotionFailure,则担保分配失败