一、对象的创建
虚拟机遇到一条new指令时,首先将去检测这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检测这个符号引用代表的类是否已被加载、解析和初始化过。如果没有,则必须先执行相应的类加载过程。在类加载检查通过后,为新生对象分配内存。
分配内存的方法:
1)“指针碰撞”:Java堆中的内存是绝对规整的,用过的在一边,空闲的在一边,中间有个指针,指针移动。
2)“空闲列表”:Java堆中的内存是绝对规整的,虚拟机将维护一个列表,记录那些内存块是可用的。
二、对象的内存布局
分为:对象头、实例数据、对齐填充
对象头:包括1)用于存储对象自身的运行时数据,如哈希码、GC分代年龄、锁状态标志、线程持有的锁等。
2)类型指针,即对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例。
实例数据:对象真正存储的信息,即在程序代码中所定义的各种类型的字段内容。
对齐填充:并不必然存在,仅有着占位符的作用。
三、对象的访问定位
Java程序需要通过栈上的reference数据来操作堆上的具体对象。
目前主流的访问方式有使用句柄和直接指针。
使用句柄:堆中会分出一块内存作为句柄池,reference中存储的就是对象的句柄地址,句柄中包含了对象实例数据与类型各自的具体地址信息。最大的好处是在对象移动是,只会改变句柄中的实例数据指针。
直接指针:reference中存储的直接就是对象地址,堆中必须考虑如何放置访问类型数据的相关数据。最大的好处是速度快。