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


    目录

    一、堆内部结构

    二、为什么进行分代

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

    四、对象分配过程


    一、堆内部结构

            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 错误。

  • 相关阅读:
    重学SpringBoot3-整合SSM
    嵌入式实时操作系统的设计与开发 (启动过程学习)
    STM32--人体红外感应开关
    我开始使用了Typescript
    【小技巧】获取matlab中cdfplot函数的x轴,y轴的数值
    贪心算法part2 | ● 122.买卖股票的最佳时机II ● 55. 跳跃游戏 ● 45.跳跃游戏II
    华为路由器忘记密码怎么恢复
    闭包随笔
    SDK动态设置自定义属性
    JAVA实现学生日常行为评分管理系统 开源项目
  • 原文地址:https://blog.csdn.net/weixin_52386948/article/details/126921046