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

前言

        我们知道Heap堆区是JVM所管理的内存最大并且内存被所有线程共享的一块区域,Heap堆区是用来存放对象实例和数组的,那Heap堆区又是如何对创建的对象进行内存分配的呢?在这里我们就要提到两个词“新生代”和“老年代”

新生代、老年代

        Heap堆是垃圾收集器(Garbage Collected)管理的主要区域,因此堆区又被称为GC堆,在JVM中堆区往往进行分带划分,所有堆区又分为新生代和老年代,目的是为了更高效的回收与分配内存

        Heap堆区可以在命令提示符通过java -xx:+PrintFlagsFinal -verstom命令查看新生代与老年代的空间分配比例:

8

         由 InitialSurvivorRatio=8 可知新生代Young(Eden/Survivor)空间的初始比例为8;代表Eden占新生代空间的80%

          由 uintx NewRatio=2 可知老年代Old/新生代Young空间的比例为2;代表老年代Old是新生代Young的2倍

综上分析可得如下图:

创建对象的内存分配

我们可以通过这段代码观察Heap堆区创建对象的内存分配过程:

public class TestOOM {
	  static String base = "aabbcc";
	  public static void main(String[] args) {
	    List<String> list = new ArrayList<String>();
	    for (int i=0;i< Integer.MAX_VALUE;i++){
	      String str = base + base;   //堆区
	      base = str;
	      list.add(str.intern());    //字符串常量池
	    }
	  }
	}

输出结果:

 

 

创建一个新对象,在堆中的分配内存。我们可以通过如下表概述对象的内存分配过程:

   总结:

           当创建一个对象时,对象首先会检查在 Eden 是否有足够存放空间,当 Eden 区存放空间足够时,就会给当前对象分配内存空间,当 Eden 区存放空间不足时,这时会触发 Young Garbage Collection,即 YGC垃圾回收,在 Eden 区实现清除策略,没有被引用的对象则直接回收。而依然存活的对象会被移送到 Survivor 区。Survivor 区分为 from(S0) 和 to (S1)两块内存区域。每次 YGC的时候,它们将存活的对象复制到未使用的Survivor 空间(s0s1),然后将当前正在使用的空间完全清除,交换两块空间的使用状态。每次交换时,对象的年龄会加+1。如果 YGC 要移送的对象大于 Survivor 区容量的上限,则直接移交给老年代。一个对象也不可能永远呆在新生代,在 JVM 中 一个对象从新生代晋升到老年代的阈值默认值是 15,可以在 Survivor区交换 14 次之后,晋升至老年代。

               当YGC之后,又会检查在 Eden 是否有足够存放空间当前对象,如果内存空间足够,则在Eden区分配内存空间,如果放不下则会检查Old区是否有足够的存放空间,如果有,则在老年代分配内存空间,否则就会进行FGC垃圾回收,之后再一次进行检查Old区是否有足够的存放空间,如果有,则在老年代分配内存空间,否则OOM抛出内存溢出异常.

 

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

雾远望

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值