详解Java中的堆内存

详解Java中的堆内存

堆是JVM运行数据区中的一块内存空间,它是线程共享的一块区域(注意了!!!),主要用来保存数组和对象实例等(其实对象有时候是不在堆中进行分配的,想要了解的可以看我之前写的博文:小白秒懂什么是栈上分配)。在堆中内存空间不足以进行分配时,就会出现OutOfMemoryError(OOM)异常。

在JDK7和JDK8中,堆中的内存结构是不同的:
在这里插入图片描述

那在JDK8中的永久代(方法区)为什么没有了那?
它被移动到了本地内存中,被称为元空间

那又有一个疑问了:为什么要把堆内存中的永久代移动到本地内存中作为元空间?
其实就是为了避免OOM异常。

年轻代又被分为三部分:Eden区和两个Survivor区。两个Survivor区大小是完全相同的,被称为from区to区。Eden区和from区、to区的比例为8 : 1 : 1。

  1. 当有一个对象新创建后,其首先会被分配到Eden区(部分对象不会首先分配到Eden区,后面会说),当Eden区内存不足时,会标记Eden区中存活的对象,进行垃圾回收,并把存活的对象移动到from区。
  2. 当Eden区内存再次不足时,再次GC,把Eden区和from区中存活的对象通过复制算法移动到to区。
  3. 再次不足时,GC,通过复制算法将Eden区和to区中存活的对象移动到from区。
  4. 就这样一直移动,当一个对象移动了15次,就被将其分配到老年代。

这就是分代回收
但有些时候对象的除此创建并不会首先被分配到Eden区,这种对象就是大对象,也就是占用大量连续内存空间的对象,其会被直接分配到老年代。

这里可能大家还会有一个疑问:为什么对象移动了15次,就会将其分配给老年代?移动的次数又是存储在哪里的?

这里就又要说到对象的内存结构了。HotSpot虚拟机中,对象在内存中的存储被分为三个部分。如图:
在这里插入图片描述

对象头又被分为
在这里插入图片描述

在MarkWord中,就存储了对象的信息(下面只列了部分):

  1. age:对象分代年龄,占4位。
  2. hashcode。
  3. biased_lock:偏向锁标识,1位。(好奇什么是偏向锁的朋友,可以搜一下锁升级,也就是synchronized这个锁的知识,我这里不深入聊锁)
  4. 等等…

age就是我们对象的GC年龄,每次移动,都会加1。age占4位,也就是2^4 - 1 = 15。所以这就是分代年龄为什么是15次,因为它能存储的最大数值是15。

JVM也提供了参数去设置分代年龄的大小,但都不能超过15。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值