一.对象的创建
1.虚拟机遇到一条new指令时,首先将区检查指令参数是否可以定位到常量池中的一个类的符号引用,并检查这个类是否已被加载,如果没有,那么必须先执行相应的类加载机制。
2.为对象分配内存空间,对象所需的内存大小在类加载完成后便完全确定。内存分配方式有两种:指针碰撞,空闲列表。指针碰撞:假设java内存绝对规整的情况下,在使用的内存放在一边,空闲的内存放在令一边,中间有作为分界点的指针,那内存分配过程就是指针向空闲内存空间移动;空闲列表:假设java堆中的内存并不规整,空闲空间与在使用的空间相互交错,那么使用一个内存使用情况的记录表,在表中找到一块合适大小的空间分配给对象。
3.虚拟机将分配到对象的内存空间都初始化为零,这一步保证了对象的实例字段在java代码中可以不赋值就可以直接使用。
4.虚拟机设置对象的对象头信息,包括类的元数据信息,对象的哈希码,对象的GC分代年龄等。
5.进行对象的初始化工作
二.对象的内存布局
1.对象头:对象头包括两部分信息,第一部分用于存储对象自身的运行时数据,如哈希码、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID等,也称为”Mark Word“。对象头的另一部分是类型指针,指向对象的类元数据,虚拟机通过这个指针确定这个对象属于哪个类。
2.实例数据:存储对象真正的有效信息,包括继承的和自身的。
3.对齐填充:仅仅起着占位符的作用,用于保证对象的大小是8字节的整数倍。
三.对象的访问定位
1.直接指针访问:引用变量中存储对象首地址,对象中存放类型元数据的相关信息。对象实例访问效率高,但当对象地址变化时,需变动引用变量。
2.句柄访问:引用变量中存储对象的句柄地址,句柄中包含了对象实例数据与类型数据各自的具体地址信息。对象实例访问效率低,但当对象地址变化时,只需改动句柄内容,引用变量不需改动。