JVM——java对象的创建和访问(二)

一、对象的创建

在Java程序运行的过程中无时无刻都有对象被创建出来。在虚拟机中单接受到创建对象(仅讨论普通对象的创建)命令时,虚拟机首先将检查这个指令的参数是否能在运行时常量池中定位到一个类的符号引用,并检查是否已经被加载、解析和初始化过。如果没有先要进行类的加载。在类加载通过后,虚拟机将为新生对象分配内存,对象所需的内存的大小在类加载完成后就可以完全确定。

1.1、内存的分配方式

内存分配有两种方式:
”指针碰撞”:如果堆的内存时绝对规整的,用过的内存和没有用过的内存时分开的,中间放着一个指针作为分界指示器。那分配内存只需要将指针向空闲的内存方向移动合适的位置即可。
“空闲列表”:如果堆中的内存不是规整的,那虚拟机需要维护一个列表,记录哪些内存块是可用的,在分配的时候从列表中找出一块足够大的空间划分给对象即可。
选择哪种分配方式由java堆是否规整决定,但是java堆是否规整则是由使用的垃圾收集器是否带有压缩整理功能决定的。这里就要结合垃圾收集方法决定, “标记-清除”使用空闲列表,“复制算法”和“标记-整理”则使用指针碰撞。
所以,在使用Serial、ParNew等带有Compact过程的收集器时,系统采用指针碰撞,而使用CMS这种基于Mark-Sweep算法的收集器时,采用空闲列表。
为保证内存分配时线程安全的,虚拟机可以采用两种方式来保证:
1.虚拟机采用CAS配上失败重试的方式保证跟新操作的原子性
2。在每一个线程的Java堆中预先分配一小块内存,称为本地内存(TLAB),哪个线程需要分配内存,就在哪个线程的TLAB上分配,只有TLAB用完并分配新的TLAB时,才需要同步。虚拟机是否使用TLAB,可以通过-XX:+/-UseTLAB参数来设定。

1.2、对象的初始化

内存分配完成后,虚拟机将分配到的内存空间都初始化为零值(不包括对象头)。这保证了对象的实例字段在代码中可以不赋初始值就可以直接使用,程序能访问到这些字段的数据类型所对应的零值(数据类型对应的零值,不是程序员意愿初始值)。
接下来虚拟机会对对象进行必要的设置,例如这个对象是哪一个类的实例、如何才能找到类的元数据信息、对象的哈希码、对象的GC分代nianl等信息,这些信息存放在对象头中。
在上面工作完成后,从虚拟机的角度看,一个新的对象已经产生。但从java程序的视角来看,对象创建才刚刚开始——方法还没有执行,所有的字段都还是类型的零值。所以,一般来说(由字节码中是否跟随invokespecial指令决定),执行new指令之后会接着执行方法,按照程序员的意愿进行初始化,这样一个真正可用的对象才算完全创建。

1.3、对象的内存布局

在HotSpot虚拟机中,对象在内存中存储的布局可以分为3块区域:对象头、实例数据和对齐填充。

1.3.1、对象头

对象头包括两部分信息,第一部分是用于存储对象自身的运行时数据,如哈希码、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等。另一部分时类型指针,即对象指向它的类元素数据的指针,虚拟机通过这个指针来去确定这个对象是哪个类的实例。

1.3.2、实例数据

实例数据部分是对象真正存储的有效信息,也是在程序代码中所定义的各种类型的字段内容,无论是从父类继承下来的,还是子类中定义的,都需要记录起来。

1.3.3、对齐填充

这一部分不是必然存在的,它仅仅是起着占位符的作用,由于HotSpot虚拟机要求对象起始地址必须是8字节的整数倍,就是说对象的大小必须是8字节的证书倍。而对象头正好是8字节的倍数(1倍或2倍),因此,当实例数据部分没有对齐时,就需要对齐填充来补全。

二、对象的访问定位

我们的java程序需要通过栈上的reference数据来操作堆上的具体对象。目前主流的访问方式由使用句柄和直接指针两种。
1.如果使用句柄访问的话,那么java堆中将会划分出一块内存来作为句柄池,reference中存储的就是对象的局部地址,而句柄中包含了对象实例数据与类型数据各自的具体地址信息。
在这里插入图片描述
2.如果使用直接指针访问,那么java堆对象的布局中就必须考虑如何让放置访问类型数据的相关信息,而reference中存储的直接就是对象地址:
在这里插入图片描述
这两种方式各有优势,使用句柄来访问就是reference中存储的时稳定的句柄地址,在对象被移动时只会改变句柄中的实例数据指针,而reference本身不需要修改。
使用直接指针的好处就是速度快,它节省了一次指针定位的时间开销。目前的HotSpot虚拟机就是使用的直接指针进行对象访问的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值