对象管理
对象的内存布局
对象头(Header)
HotSpot虚拟机的对象头包括两部分的信息
第一部分存储对象自身的运行时数据,如哈希码,GC分代年龄,锁状态标识,线程持有的锁,偏向线程ID,偏向时间戳。这部分数据的长度在32位和64位虚拟机中的长度为32bit和64bit
另一部分是类型指针,即对象指向他的类元数据的指针,虚拟机通过这个指针确定这个对象是哪个类的实例。如果Java对象是一个数组,那在对象头中还必须有一块用于记录数组长度的数据。
实例数据(Instance Data)
真正存储的有效信息。也是程序代码中定义的各种类型的字段内容。无论是从父类继承下来的,还是从子类中定义的,都需要记录起来。这部分的存储信息会受到虚拟机分配策略参数(FieldsAllocationStyle)和字段在Java源码中定义的顺序的影响。
对齐填充(Padding)
对齐填充不是必然存在的,没有特别的含义,仅仅起着占位符的作用。HotSpot要求对象其实地址必须是8的整数倍。对象头部分正好是8字节的倍数,而实例数据部分则不一定,所以这部分需要对齐填充。
对象的访问定位
句柄访问方式:java堆中将划分出一块内存来作为句柄池,reference中存储的就是对象的句柄地址,而句柄中包含了对象实例数据和类型数据各自的具体地址信息。
指针访问方式:reference变量中直接存储的就是对象的地址,而java堆对象一部分存储了对象实例数据,另外一部分存储了对象类型数据。
这两种对象访问方式各有优势:
1. 使用句柄来访问的最大好处就是reference中存储的是稳定的句柄地址,在对象被移动(垃圾收集时移动对象是非常普遍的)时只会改变句柄中的实例数据指针,而reference本身不需要修改;而缺点是访问对象时需从句柄池中获取具体位置后再定位具体的内容,由于对象的访问在java中非常频繁,故这类开销积少成多也是一项非常可观的执行成本。
2. 使用直接指针访问方式的最大好处就是速度更快,它节省了一次指针定位的时间开销。我们常用的Sun HotSpot虚拟机而言,它是使用第二种方式进行对象的访问的。