一、对象创建的过程:当虚拟机遇到一条含有New的指令时,会进行一系列对象创建的操作。
- 检查常量池中是否含有带创建对象所属类的符号引用
a) 如果含有的话,直接进行下一步
b) 如果常量池中没有这个符号引用的话,说明这个类还没有被定义,回报ClassNotFounddError的异常。
2.检查该符号引用所属的类是否已经被加载到JVM中
a) 如果已经被加载到JVM中,则直接进行下一步
b)如果这个符号引用所属的类还没有被加载到JVM中,则会先找到这个类的Class文件,把它加载到方法区。
3.根据方法区中该类的信息确定创建该类的对象需要的空间大小。
4.在堆内存中为该对象分配内存空间。
a) 分配内存空间的方法主要有两种:指针碰撞和空闲列表。
b) JVM选用哪一种内存分配方法主要取决于该虚拟机使用哪一种垃圾收集器。
c) 指针碰撞法主要适用于复制法和标记-整理法
d) 空闲列表法主要适用于标记-清理法
5.为该对象的成员变量进行初始化
6.设置对象头信息
7.调用该对象的构造方法进行初始化
至此,对象在虚拟机中的创建过程就已经完成了。
二、对象的内存模型
- 对象头:主要包括对象在运行过程中需要的信息,可能还会包括类型指针(用于指示对象是属于哪一个类);如果对象是一个数组的话,对象头中还会包括数组的长度。
- 实例数据:该对象的成员变量的值
- 补充对齐:为了保证创建对象的长度是8个字节长度的倍数。主要是因为对象头虽然一定是8字节的整数倍,但是实例数据部分的长度是不确定的。
三、访问对象的过程
- 引用类型的变量中存放的是一个地址,根据地址类型的不同,对象有不同的类型访问方式。
- 句柄访问方式:在堆内存空间中有一个句柄池,里边存放的是对象在内存中的地址和对象所属类信息。这种情况下的引用类型的变量中存放的是对象在句柄池中的地址,通过句柄池中的地址然后才能访问到该对象。
- 直接访问方式:引用类型的变量中存放的就是该对象在内存的实际地址,这样通过应用类型的变量能够直接访问到该对象。但是需要在该类所在的内存空间中增加额外的策略储存该对象所属类的类信息的地址。
- 两者的比较:HotSpot采用直接指针方式访问对象,因为它只需一次寻址操作,从而性能比句柄访问方式快一倍。但它需要额外的策略存储对象在方法区中类信息的地址。