一文读懂JVM对象创建及内存分配机制上

各位小伙伴,当我们new一个对象的时候,对象到底是怎么生产出来的呢,我们这篇说一说对象生成的过程和内存的分配机制,面试的时候可以扯一扯,绝对是加分项。1.加载类时检查虚拟机在执行的过程中,执行到new关键字(new关键词、对象克隆、对象序列化等)的时候,第一步是先去检查这个指令的参数对应的符号引用是否在常量池中,其对应的类是否已经被加载解析和初始化,如果已经有,就代表此类已经被加载过了,如果吗,没有就说明类还没有被加载,那就要执行类记载的整个过程。2.内存的分配在类加载过程完成后,就要对新创建的对
摘要由CSDN通过智能技术生成

各位小伙伴,当我们new一个对象的时候,对象到底是怎么生产出来的呢,我们这篇说一说对象生成的过程和内存的分配机制,面试的时候可以扯一扯,绝对是加分项。
在这里插入图片描述

1.加载类时检查

虚拟机在执行的过程中,执行到new关键字(new关键词、对象克隆、对象序列化等)的时候,第一步是先去检查这个指令的参数对应的符号引用是否在常量池中,其对应的类是否已经被加载解析和初始化,如果已经有,就代表此类已经被加载过了,如果吗,没有就说明类还没有被加载,那就要执行类记载的整个过程。

2.内存的分配

在类加载过程完成后,就要对新创建的对象进行分配内存的操作,那么对应所需要的内存具体大小是如何确定的呢,其实对象所需内存的大小在类加载完成后就可以完全确定了,虚拟机只需要在java堆中划分出相应大小的固定的一块内存空间即可。
但是在分配内存这个过程中有两个问题:
1.如何划分内存。
2.在并发情况下, 可能出现正在给对象A分配内存,指针还没来得及修改,对象B又同时使用了原来的指针来分配内存的情况。

虚拟机有两种内存分配方法,一种是“指针碰撞”,一种是“空闲列表”,java默认采用的是指针碰撞,指针碰撞针对于规整的java堆,被使用的内存全都集中在堆的一边,而另一边都是空闲的内存,当需要分配固定大小的内存时候,只需要将内存的指针(分界点的指示器)从当前使用的位置向后挪动相应大小即可。当堆内存分配不是规整的时候,被使用的内存和没有被使用的内存交错相间,虚拟机很难找到一块固定大小且连续的内存空间,这时候指针碰撞就很难发挥出作用,这个时候虚拟机采用的是空闲列表,空闲列表是用来维护哪些内存块是空闲的,在进行分配内存的时候,只需要去空闲列表中找到一块大小合适且连续的内存块就可以了,然后再把这块内存空间在空闲列表上更新其记录。

解决并发问题的方法:
CAS(compare and swap): 虚拟机采用CAS配上失败重试的方式保证更新操作的原子性来对分配内存空间的动作进行同步处理。

本地线程分配缓冲(Thread Local Allocation Buffer,TLAB): 把内存分配的动作按照线程划分在不同的空间之中进行,即每个线程在Java堆中预先分配一小块内存。通过-XX:+/-UseTLAB参数来设定虚拟机是否使用TLAB(JVM会默认开启-XX:+UseTLAB),-XX:TLABSize 指定TLAB大小。

3.初始化零值

内存分配完成后,虚拟机需要将分配到的内存空间都初始化为零值(不包括对象头), 如果使用TLAB,这一工作过程也可以提前至TLAB分配时进行。这一步操作保证了对象的实例字段在Java代码中可以不赋初始值就直接使用,程序能访问到这些字段的数据类型所对应的零值。

4.设置对象头

初始化零值之后,虚拟机要对对象进行必要的设置,例如这个对象是哪个类的实例、如何才能找到类的元数据信息、对象的哈希码、对象的GC分代年龄等信息。这些信息存放在对象的对象头Object Header之中。

在HotSpot虚拟机中,对象在内存中存储的布局可以分为3块区域:对象头(Header)、 实例数据(Instance Data)和对齐填充(Padding)。HotSpot虚拟机的对象头包括两部分信息,第一部分用于存储对象自身的运行时数据, 如哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时 间戳等。对象头的另外一部分是类型指针,即对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例。

32位对象头:

在这里插入图片描述

64位对象头:

在这里插入图片描述

5.执行方法

执行方法,即对象按照程序员的意愿进行初始化。对应到语言层面上讲,就是为属性赋值(注意,这与上面的赋零值不同,这是由程序员赋的值),和执行构造方法。

对象大小与指针压缩
对象大小可以用jol-core包查看,引入依赖

<dependency>
    <groupId>org.openjdk.jol</groupId>
    <artifactId>jol-core</artifactId>
    <version>0.9</version>
</dependency>
  import org.openjdk.jol.info.ClassLayout;

/**
 * 计算对象大小
 */
public class 
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

斯巴达人

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

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

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

打赏作者

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

抵扣说明:

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

余额充值