创建对象在堆区如何分配内存

目录

一、堆内部结构

二、为什么进行分代

三、为什么要将幸存者区分为两个部分?

四、对象分配过程


一、堆内部结构

        Java JDK7及以前逻辑上被分为三部分:新生代、老年代、永久代 。

         Java JDK8及以后被分为了:新生代、老年代、元空间;元空间存储的对象与永久代相同,区别是:元空间并不在jvm中,使用的是本地内存。

为什么要移除永久代?为融合HotSpot JVM与JRockit VM而做出的改变,因为JRockit没有永久代。

二、为什么进行分代

        将生命周期很短的对象放在新生代,将生命周期很长的对象放在老年代,因为在每次GC时,垃圾回收器都会去判断当前对象是否可以被回收,而这些生命周期很长的对象每次都被垃圾回收器扫描,但每次都不回收,故而可以将这些对象放在老年代,并减少对老年代的GC次数,从而将GC的重心放在新生代上。 

        通过这两个区域对象的生命周期不同,也可以设置不同的垃圾回收算法,比如对新生代中的对象采用复制算法,因为该区域的对象生命周期短,消亡快,所以当发生GC时并不会存在太多存活的对象,而对老年代则采用标记-清除算法。

        精简解释:将对象根据存活概率进行分类,对存活时间长的对象,放到固定区,从而减少扫描垃圾时间及GC频率;针对分类进行不同的垃圾回收算法,对算法扬长避短。

三、为什么要将幸存者区分为两个部分?

        主要为了解决碎片化,因为回收一部分对象后,剩余对象占用的内存不连续,也就是碎片化,过于严重的话,当前连续的内存不够新对象存放就会触发GC,这样会提高GC的次数,降低性能,当S0 GC后存活对象转移到S1后存活对象占用的就是连续的内存。

比如一开始只有Eden区和From中有对象,To中是空的。此时进行一次GC操作,From区中对象的年龄就会+1,我们知道Eden区中所有存活的对象会被复制到To区,From区中还能存活的对象会有两个去处;若对象年龄达到默认年龄为15岁,此时对象会被移动到Old区, 如果Eden区和From区 没有达到阈值的对象会被复制到To区。此时Eden区和From区已经被清空。

这时候From和To交换角色,之前的From变成了To,之前的To变成了From。无论如何都要保证To的Survivor区域是空的。

四、对象分配过程

  • 创建的对象首先存放在Eden区;
  • 当Eden区的空间满了以后,此时创建对象便会触发GC(Minor GC),将Eden区中存活的对象放入幸存区,然后清除Eden区;
  • 当触发Eden区的GC时,会将Eden区中还存活的对象放入幸存区S0;
  • 当Eden区满了再次触发GC时,会将Eden区中存活的对象和幸存者S0中仍然存活的对象放入幸存区S1;
  • 若再一次触发Eden区的GC,则将存活的对象又重新放回幸存区S0,依次循环;
  • 存活的对象被放入幸存区一次,年龄就会加1,当对象的年龄到达15岁时,该对象就会被晋升到老年代;
  • 只有Eden区满时才会触发GC,此时垃圾回收器会对Eden区和Survivor区进行清理,Survivor区满并不会触发GC,而且GC完成后,Eden区是一个空的状态;
  • 当要创建的对象内存超过Eden区空间时,该对象会被直接晋升到老年代;
  • 若是老年代仍然放不下,则触发一次在老年代的GC(Full GC);
  • 如果GC完成后还是放不下,则出现 OutOfMemoryError: Java heap space 错误。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值