JVM对象的创建

对象的创建

遇到new关键词时,虚拟机都做了什么

1.检查该对象类是否已经进行过初始化等过程,如果没有,就先进行初始化过程,即类加载过程(静态变量是存储在方法区中,而正常的方法变量是存储在栈中的局部变量表中的)。
2.类加载完成之后,需要给对象分配内存空间,对象所需的大小会在类加载之后确定。
分配内存空间有两种方法:指针碰撞以及空闲列表
指针碰撞是相当于把堆内存分配为空闲区以及非空闲区两部分,所以需要一个指针进行标记,标记的一侧是已分配的空间,另一侧是未分配的空间。
空闲列表是堆内存中已分配与未分配的空间是相互交错的,所以不能使用指针,因此使用列表来记录内存空间上有哪些是可以使用的,哪些是没有使用的。
因此,区别这两种方式的关键是内存空间的分配是否是规整的,而内存空间是否规整,是跟JVM垃圾收集器是否有压缩整理功能决定的,如果具有compact功能,那么就使用碰撞指针,如果不具有,那么使用空闲列表方法。
同时分配空间时还需要注意线程的安全问题,因为有可能JVM正在给A对象分配内存,但是指针还没有修改,但是B对象也需要使用原来的指针进行操作,就会出现线程安全问题。
解决办法:1.使用CAS配上失败重试将更新操作变成一个原子操作。
2.把不同线程的内存分配的动作分配在不同的内存空间上进行。
4.将该对象分配到的所有空间都初始化为零值(不包括对象头),这样保证了在分配对象内存结束之后,程序可以直接访问到该对象,使该对象不赋初值也可以使用。
5.对该对象的对象头进行设置(Object Header)。
此刻,从虚拟机的角度,一个拥有自己内存的对象已经创建成功,但是对于用户来说,还并没有进行构造方法,以上一些,只是一个new 关键字JVM做的事情。

对象内存的布局

对象内存在以上过程中分布结束,那么这么一块内存,在HotSpot内部是怎么布局的呢?
分为三个部分:对象头(Object Header)、实例数据(Instance data)、对齐填充(Padding)。

对象头

对象头的内容分为两部分
第一部分是对象自身的运行数据:哈希码、GC分代年龄、锁状态、线程持有锁等等,官方称之为“Mark Word”。
第二部分是存储对象的类指针,JVM通过该指针,知道该对象是什么类的实例。(但是并不是所有类都需要有类指针),如果该对象是数组,对象头中还必须要有一部分内存用来记录数组的长度。

实例数据

真正对程序员来说有用的数据,存储的规则是相同宽度的字段会被分配到一起存储,在满足该前提的情况下,父类的实例数据会先于子类的实例数据存储。

对齐填充

仅仅起到占位符的作用。

对象的访问

通过reference类(在栈中,更准确地说,是在局部变量表中)访问
reference访问对象有两种模式:
句柄和直接指针。

句柄

如果使用句柄,JVM会在内存中分出一块地方,叫做句柄池,池内有两种指针,一种指向对象实例数据的指针,另一种指向对象类型数据的指针。
句柄

直接指针

直接指针会直接指向对象实例数据,但是除此之外,就必须要考虑放置对象的类型数据的指针。
直接指针

这两种访问方法各有自己的优势,对于使用句柄来说,当对象发生移动,改变的时候只需要改变句柄内部的实例数据的指针,并不需要对reference进行修改,对于直接指针来说,访问对象的时候,减少了一次指针定位的开销。
HotSpot虚拟机使用的是直接指针的方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值