一. 对象的创建
1. 虚拟机执行new指令,首先去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表类是否已被加载,解析和初始化过,如果没有先执行类加载过程
2. 类加载检查通过后,虚拟机将为新生对象分配内存。对象所需内存的大小在累加在完成后便可以确定。
二. 对象的内存布局
描述:在HotSpot虚拟机中,对象在内存中存储的布局可以分为3块区域:对象头(Header), 实例数据(Instance Date)和对齐填充(Pading);
1.对象头包括两部分,
第一部分用于存储对象自身的运行时数据,如哈希码(HashCode),GC分代年龄,锁状态标志,线程持有的锁,偏向线程ID,偏向时间戳等,ps:如果对象是一个java数组 对象头中还必须记录数组的长度。
第二部分时类型的指针,即对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象时那个类的实例。
2. 实例数据
实例数据是对象真正存储的有效信息,也是在程序代码中所定义的各种类型的字段内容。无论是从父类继承下来的,还是在子类中定义的,都需要记录起来。这部分的存储顺序会受到虚拟机分配策略参数和字段在java源码中定义顺序的影响。
HotSpot 默认的分配策略为 long / double / int / short / bytes /boolen / oop 从策略中可以看出 相同宽度的字段总是被分配在一起。
3.对齐填充
对齐填充并不是必然存在的,也没有特别的含义,它仅仅起着占位符的作用,
由于HotSpot VM 的自动内存管理系统要求对象起始地址必须是8字节的整数倍,对象的大小必须是8字节的整数倍,而对象头部分正好是8字节的倍数(1倍或2倍),因此当对象实例数据部分没有对齐时,就需要通过对齐填充来补全
三,对象访问定位
对象定位目前有2种主流的方式:句柄 和 直接指针两种方式
句柄方式:
如果使用句柄访问的话,那么java堆中将会划分出一块内存来作为句柄池,reference(引用)中存储的就是对象的句柄,而句柄中包含了对象实例数据与类型数据各自的具体地址信息
指针方式:
如果使用直接指针访问,那么java堆对象的布局中就必须考虑如何方式访问类型数据的相关信息,而reference中存储的直接就是对西那个的地址
两种方式的优劣:
使用句柄来访问:reference中存储的就是稳定的句柄地址,在对象被移动(垃圾收集时移动对象是非常普遍的行为)时只会改变句柄中的实例数据指针,而reference本身不需要修改
使用直接指针访问:访问速度快,它节省了一次指针定位的时间开销,由于对象的访问在java中非常频繁,因此这类开销积少成多后也是一项非常客观的执行成本,
网友评论