一、对象的创建
1、类加载: 虚拟机在遇到一条new指令时候,检查类是否已被加载、解析、初始化过,如果没有,则执行类加载过程。
2、分配内存:类加载完成后,则为新对象从java堆上分配内存,分配内存有两种方式:指针碰撞和空闲列表
Java堆中内存是绝对完整的,用过和空闲的内存分别放在一边,中间用一个指针作为分界点的指示器。分配内存时就是将指针向空闲内存区域挪动一段与对象同样大小的距离。
Java对中内存不是规整的,用过的和空闲的内存相互交错,这种情况,虚拟机就必须维护一个列表,记录哪些内存是可用的。分配时候,从列表中找到一块足够大的内存划分给对象。
选用哪种分配方式由Java堆是否规整决定,是否规整又由垃圾收集器是否带有压缩整理功能决定。
3、分配内存时,在并发情况下也并不是线程安全的,可能出现正在给A分配内存,指针还没来得及修改,对象B又同时使用原来的指针来分配内存情况。
两种解决方案:
4、必要设置:内存分配完成后,会把内存空间都初始化为零值,同时虚拟机会对对象做一些必要的设置
如:这个对象是哪个类的实例、如何才能找到类的元数据信息、对象的哈希值、对象的GC分代年龄等信息。这些信息存放在对象头(Object Header)中。
5、init方法执行:完成以上流程,虚拟机已经完成了一个对象的创建,但从Java程序来看,对象创建才刚开始,所有字段都还为零。
所以紧接着会执行init方法(由字节码中是否跟随invokespecial指令决定),把对象按照程序员的意愿进行初始化。
二、对象的内存布局
在HotSpot虚拟机中,对象在内存中储存的布局可分为3块区域:对象头(Object Header)、实例数据(Instance Data)、对象填充(Object Padding)。
1、对象头包括两部分数据
2、实例数据
存放对象真正有效信息,程序代码中所定义的各种类型的字段内容。无论是父类继承的还是子类定义的,都会记录起来。
3、对齐填充
不是必然存在的,仅仅起着占位符作用,因为HotSpot要求对象大小必须是8字节的整数倍。因此对象数据没有对齐时,就需要通过对其填充来补全。
三、对象的访问定位
对象访问取决于虚拟机,目前主流两种方式有句柄和直接指针两种。
两种方式各有优势