从 JVM 虚拟机角度去看一个对象的创建过程

引言

本篇文章从 JVM 虚拟机角度讲述对象的创建过程,中间会提到 JVM 运行时数据区域的知识(点击这里查看 JVM 运行时数据区域)、类加载过程、CAS、设置对象头 JAVA 内存布局 等后续都会各抽出一篇文章单独去讲,暂不在这篇文章去讲。

一、对象的创建

Student stu = new Student();

其实当你 new 一个对象后,经过编译后,在 JVM 虚拟机中执行的时候其实做了很多的事情。

二、虚拟机遇到 new 指令

当虚拟机执行时,遇到一个 new 指令时,会首先去检查这个指令的参数是否能够在常量池中定位到一个类的符号引用,并检查这个类是否被加载、解析和初始化(我一般称为类加载三件套),如果没有的话,必须去执行相应的类加载过程。

三、分配内存空间

在类加载后呢,虚拟机将会为这个新生的对象去分配内存空间,而这个对象所需要的内存空间在类加载完成后就能完全确定下来。
为对象分配内存空间的任务其实就是把已经确定下来的内存从 JAVA 堆中划分出来,划分的方法有两种。

1、堆中内存绝对规整过

在这里插入图片描述
堆中的内存绝对规整过后,内存空间中所有被用过的内存放到一边,而没有用过的内存放到另一边,中间放着一个指针作为分界点的指示器,当进行分配内存的时候分界点指针会向空闲空间方向挪动一段与对象所需内存空间大小相等的距离,这种分配方式称为 “ 指针碰撞 ”。

2、堆中内存没有经过绝对规整过

如果堆中的内存是没有经过绝对规整过的,已被使用过的内存和没有被使用过的内存是相互交错在一起的,那么就没有办法简单地进行指针碰撞了,这时呢,虚拟机就会维护一个列表,这个列表叫做 “ 空闲列表 ”,这个列表会记录哪些内存块是可用的,在分配的时候会从列表中找到一块足够大的内存空间划分给这个对象实例,并更新空闲列表表中的记录。

上面就是两种分配的方式,这两种分配方式的选择是取决于 JAVA 堆所采用的垃圾回收器是否带有空间压缩整理的能力决定。因此,当使用 Serial、ParNew 等带压缩整理过程的收集器时,系统所采用的分配算法是 “ 指针碰撞 ” ,简单而又高效;而当使用 CMS 这种基于清除算法的收集器时,理论上就只能采用较为复杂的 “ 空闲列表 ” 来进行分配内存。

3、并发情况下划分空间

上面两种是分配内存空间的两种方式,而在并发情况下还需要去考虑一个问题,即对象创建在虚拟机中是非常频繁的行为,即使仅仅是修改一个指针所指向的位置,在并发情况下也不是线程安全的,可能会出现正在给 A 对象分配内存,指针还没有来得及进行修改,对象 B 又同时使用了原来的指针来进行分配内存的情况。
解决这个问题也有两种方式:
第一种是对分配内存空间的动作进行同步处理,其实,实际上虚拟机是采照 CAS 配上失败重试的方式保证更新操作的原子性。

CAS 我在这里简单提一下,其实就是多个处理器同时修改同一个共享变量值的时候,先把内存中的值复制一下(复制的值比作 A),然后准备新的值(新的值比作 B),将新的值写到内存中的时候,会先把 A 跟内存中的值比较一下,如果相等就会将 B 修改到内存中,不相等就不修改;

第二种是是把内存分配的动作按照线程划分到不同的空间中运行,其实就是每一个线程都有一块属于自己的区域,这个区域叫本地线程分配缓冲区(Thread Local Allocation Buffer,简称为 TLAB),要是哪个线程需要分配内存的时候就现在自己那个缓冲区域分配,自己那个缓冲区域分配完了以后,内存会再给你分配新的缓冲区域,分配的时候会同步锁定。

四、初始化

给这个对象分配空间完成以后,虚拟机会将分配到的内存空间(不包括对象头)都初始化为零值,如果使用了 TLAB 的话,这一项工作也可以提前至 TLAB 分配时顺便执行了。

这一步操作呢,是保证对象的实例字段在 JAVA 代码中不赋初始值就能使用,能够让程序访问到这些字段的数据类型所对应的零值。

五、对象的设置

接下来,虚拟机还要对对象进行必要的设置,比如说,这个对象是哪个类的实例、怎么才能找到这个类的元数据信息、对象的哈希码、对象的 GC 分代年龄等信息,这些信息存放在对象的对象头中。
还会根据虚拟机的运行状态的不同,比如说,是否启用偏向锁等,对象头也会有不同的设置方式,关于对象头的设置请看这篇文章 JAVA 内存布局


六、总结

从 JVM 虚拟机角度去看创建一个对象,大体的流程图就是这样的:
在这里插入图片描述

到这里的话从虚拟机的角度来讲其实就完成它的工作了,当然,后面还会有很多工作,比如Class文件中的 init() 方法还没有执行,对象的值还没有按照预想的意图构建好等,当然这都是从 JAVA 程序的角度去讲了,本篇文章只是从 JVM 虚拟机角度去讲。

本篇文章主要来源于《深入理解JAVA虚拟机》和《JAVA并发编程的艺术》


End


  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值