JVM 中对象的创建过程

对象的内存分配

在这里插入图片描述
当虚拟机遇到new指令时,首先检查类是否存在是否被类加载器加载,如果没有,那必须先执行类加载,然后再进行分配内存初始化。

检查加载

就是字面意思 :检查类是否已经被加载、解析和初始化过。

分配内存

分配内存就是虚拟机为新生对象分配内存,就是从java堆中为对象划出一块内存。

划分内存的方式

指针碰撞

在这里插入图片描述
我们把内存空间看成一个矩形(上图的整个区域),如果堆中的这个内存绝对规整,所有用过的内存都放在一边(如上图的红色区域),空闲的区域放在一边(上图的白色区域),中间放着一个指针作为分界点的指示器(上图箭头),那么分配内存就是指针向着空闲区域移动一段与对象相同大小的距离,这种分配就是指针碰撞

空闲列表

在这里插入图片描述
如果堆中的内存不是规整的,使用过的内存与未使用的内存相交错(上图),那么就没有办法是用指针碰撞了,那么虚拟机就得建立一个列表维护这个内存,在列表上标记哪块使用过哪块没有使用过,当需要分配对象时,虚拟机会找一块区域划分给对象,然后更新在列表上,这种方式为空闲列表

选择哪种分配方式由java堆是否规整来决定的,而java堆是否规整又由于所采用的垃圾回收器是否带有压缩整理功能决定的。

解决并发安全

?考虑?
我们都知道java本是多线程的,所以在对象创建在虚拟机中是非常频繁的操作,即使是仅仅修改一个指针所指向的位置(指针碰撞),在并发情况下并不是线程安全的,可能会出现正在给对象A分配内存,指针还没来的及修改,同时B又同时使用了原来的指针来分配内存情况,这样就会出现问题。
为了解决这样的问题又两种方案:

CAS机制

在这里插入图片描述
虚拟机在分配前先读取当前的内存值,如果有值,就在找下一个,知道没有,然后做预处理,然后再与实时值相比较,如果不相等那么就在来一次,如果相等则分配成功。

TLAB(本地线程分配缓冲)

简单的说就是每个线程在java堆中都预先分配一块私有内存,也就是本地线程分配缓冲(Thread Local Allocation Buffer,TLAB)。
JVM在线程初始化的时候,同时也会申请一块指定大小的内存,只给当前线程使用,这样每个线程都单独拥有一个区域,如果需要分配内存,就在自己的区域上分配,这样就不存在竞争的情况,可以大大提升分配效率,当自己的区域不够时,再从新申请一块继续使用。

TLAB的目的是在为对象分配空间时,让每个java应用线程能在使用自己的专属指针来分配空间,减少同步开销。
还有就是TLAB只是让每个线程有私有的分配指针,但自己内存的对象空间还是给所有线程访问的,只是其他线程不能在这个区域分配而已,当一个TLAB用满时(指针top撞上分配极限的end),就新申请一个TLAB。

内存空间初始化

内存分配完成后,虚拟机需要将分配到的内存空间都初始化为零值(如 int 值为 0,boolean 值为 false 等等)。这一步操作保证了对象 的实例字段在 Java 代码中可以不赋初始值就直接使用,程序能访问到这些字段的数据类型所对应的零值。
在这里插入图片描述

设置

接下来,虚拟机要对对象进行必要的设置,例如这个对象是哪个类的实例、如何才能找到类的元数据信息(Java classes 在 Java hotspot VM 内部表示为类 元数据)、对象的哈希码、对象的 GC 分代年龄等信息。这些信息存放在对象的对象头之中。

对象初始化

在上面工作都完成之后,从虚拟机的视角来看,一个新的对象已经产生了,但从 Java 程序的视角来看,对象创建才刚刚开始,所有的字段都还为零值。 所以,一般来说,执行 new 指令之后会接着把对象按照程序员的意愿进行初始化(构造方法),这样一个真正可用的对象才算完全产生出来。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值