Java中一个对象的创建过程
step1:检查该类是否被加载
当JVM执行一条new指令时,首先要去常量池中查找该类的符号引用。
当在常量池中查找到该类的符号引用,就说明该类已经被类加载(方法区保存了该类的类加载信息),就可以继续执行后续操作。
当在常量池中查找不到该类的符号引用,说明该类还没有被类加载,因此就要用类加载器执行该类的类加载过程。类加载完毕后执行后续操作。
step2:为对象分配内存
类加载之后,就要为新生对象分配内存空间。对象的大小在类加载的过程中就已经确定。分配空间有两种方式:1.指针碰撞;2:空闲列表。选择那种分配方式取决于堆内存是否规整,而堆内存是否规整取决于GC使用的垃圾回收器是否有压缩整理功能。
内存分配方式
1.指针碰撞:将用过的内存放在一边,没用过的内存放在另一边。中间有一个分界指针。需要分配内存时,将指针想没用过的内存方向移动对应内存大小的位置即可。这种情况适用于内存绝对规整。
2.空闲列表:JVM维护了一个列表,记录那些内存块未被使用。当需要分配内存时,JVM选择一块合适大小的内存块分配给对象,并更新空闲列表。该方法适用于内存不规整的情况。
线程安全问题
1.采用同步方法,使用CAS来保证操作的原子性。
2.TLAB:每个线程现在eden区分配一小块内存,JVM在给对象分配内存时,首先在TLAB分配。当对象大于TLAB中剩余内存时,采用CAS进行内存分配。
step3:初始化零值
内存分配完毕后,将对象的内存空间初始化为零值,这样即使对象没有被赋初值,也能够被直接使用。
step4:设置对象头
分配完内存空间,初始化零值之后,虚拟机还需要对对象进行其他必要的设置,设置的地方都在对象头中,包括这个对象所属的类,类的元数据信息,对象的hashcode,GC分代年龄等信息。
step:5:执行init方法
执行完以上步骤之后,在JVM层面,一个对象就算创建成功了。但是从Java程序层面,对象的创建才刚开始。对象的所有字段还都为零值。这时候调用init的方法,按照意愿对对象初始化,调用init方法之后对象才算真正创建成功。
|