一、对象的创建过程
当虚拟机遇到一条含有new的指令时,会进行一系列对象创建的操作:
1.检查常量池中是否有即将要创建的这个对象所属的类的符号引用。
2.检查这个符号引用所代表的类是否已经被JVM加载。
3.根据方法区中该类的信息确定该类所需的内存大小
4.从堆中划分一块对应大小的内存空间给新的对象
5.为对象中的成员变量赋上初始值(默认初始化)
6.设置对象头中的信息
7.调用对象的构造函数进行初始化
七步骤:检查符号引用、检查JVM是否加载、确定对象所需大小、分配内存空间、默认初始化、设置对象头中的信息、执行构造函数。
二、对象的内存模型
对象在内存中分为三个部分:
1.对象头
2.实例数据
3.对齐补充
1.对象头
对象头中记录了对象在运行过程中所需要使用的一些数据:哈希码、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等。
此外,对象头中可能还包含类型指针。通过指针能确定这个对象所属哪个类。
此外,如果对象是一个数组,那么对象头中还要包含数组长度。
2.实例数据
实例数据部分就是成员变量的值,其中包含父类的成员变量和本类的成员变量。
3.对齐补充
用于确保对象的总长度为8字节的整数倍。
HotSpot要求对象的总长度必须是8字节的整数倍。对象头一定是8字节的整数倍,但是实例数据部分的长度是任意的,因此需要补充字段确保整个对象的总长度为8的整数倍。
三、访问对象的过程
引用类型的变量中存放的是一个地址,那么根据地址类型的不同,对象有不同的访问方式:
目前的主流的访问方式有使用句柄访问和直接指针访问两种。
1.句柄访问
Java堆中会划分出一块内存作为句柄池,栈中的reference指向对象的句柄地址,句柄中包含了对象实例数据和类型数据各自的具体地址信息,如下图所示。
2.直接指针访问
reference中存储的就是对象地址。
3.比较
总的来说,这两种对象访问定位方式各有千秋。使用句柄访问的最大好处就是reference中存储的是稳定的句柄地址,对象被移动(垃圾收集时移动对象是非常普遍的行为)时只会改变句柄中的实例数据指针,reference本身不需要修改;而使用直接指针访问的最大好处就是速度快,节省了一次指针定位的时间开销。
HotSpot采用直接指针方式访问对象,因为它只需一次寻址操作,从而性能比句柄访问方式快一倍。但它需要额外的策略存储对象在方法区中类信息的地址。
参考:
来自 <https://blog.csdn.net/justloveyou_/article/details/71189093>
来自 <https://blog.csdn.net/u010425776/article/details/51190801>