java中对象的创建

我们知道,Java对象实例是由Java运行时数据区的堆所管理的。我们以HotSpot为例,来探讨关于Java对象的创建对象的内存布局对象的访问定位

对象的创建:

1、当java虚拟机遇到new指令时,会通过new指令后的参数到常量池中定位这个类的符号引用,检查这个符号引用代表的类是否被加载,连接,初始化,如果没有,则要先执行相应的类加载过程。

2、在类加载检查通过后,虚拟机就要为新生对象分配内存。内存的分配主要有两种方式:1、指针碰撞,2、空闲列表。

3、内存分配完成之后,Java虚拟机必须将分配到的内存(对象头除外)赋初始值零。这一步保证了对象的实例字段在Java代码中不用赋初始值就可以使用。

4、接下来,Java虚拟机还会对对象进行一系列的设置。如这个对象是哪个类的实例,如何找到类的元数据信息,对象的GC分代年龄等信息。这些信息存放在对象的对象头之中。

5、至此,从虚拟机的角度来看,一个对象的创建已经结束了,但是从Java程序来看,对象的创建刚刚开始——构造函数,即class文件中的<init>()方法还没有执行。一般来说,new指令后面会执行<init>()方法,这样一个真正的对象才被构造出来。

对象的内存布局:

在HotSpot虚拟机中,对象的内存布局分为三部分:对象头实例数据对齐填充

对象头包含两类信息:1、用于存储对象自身的运行时数据,比如哈希码、GC分代年龄、锁状态标志等。2、用于存储类型指针,即对象指向自己类型元数据的指针,Java虚拟机可以通过这个指针确定对象是哪个类的实例。

实例数据则是对象真正存储的有效的信息,即我们在类中所定义的各种类型的字段,无论是父类所继承下来的,还是在子类中所定义的。

对齐填充并不是必须存在的,它起着占位符的作用。

对象的访问定位:

对象的访问定位是通过栈中的reference数据来操作堆上的具体对象。主流的访问方式有两种:使用句柄直接指针

句柄访问会在堆上开辟出一块空间来存储实例数据和类型数据的各自地址信息,这块内存空间就是句柄池,而reference存储的就是句柄池的地址信息。

直接指针方式,reference存储的直接就是对象地址。这种方式需要考虑在对象的内存布局中如何放置类型数据的相关信息。

 

TLAB(Thread Local Allocation Buffer):每个线程在java堆中预先分配一块内存。利用-XX:+/-UseTLAB来启用或禁止使用TLAB

 

参考:《深入理解java虚拟机》第三版——周志明

 

posted @ 2022-05-19 20:40  知识怪人  阅读(106)  评论(0编辑  收藏  举报