对象的创建
-
收到一条字节码new指令时,首先检查这个指令是否能在常量池中定位到一个类的符号引用,并检查这个符号引用代表的类是否已被加载、解析和初始化过。如果没有,则进行相应的类加载过程
-
接下来进行内存的分配,对象所需的内存大小在类加载完成后便可确定,为对象分配空间等同于在堆中划分一块确定大小的内存块。
堆中内存情况有两种:绝对规整,非绝对规整。
绝对规整的内存,是被分为空闲内存和使用过的内存,中间放着一个指针作为分界点的指示器,那么分配内存就仅仅把那个指针向空闲空间方向挪动一段与对象大小相等的距离,这种分配方式为“指针碰撞”。
非绝对规整的内存,是空闲内存和使用过的内存交错,虚拟机就必须维护一张列表,记录哪些内存块可用,在分配内存的时候,就是从列表中找到一块足够大的空间划分给对象实例,并更新表中数据,这种分配方式为“空闲列表”
而Java堆是否规整又和垃圾收集器是否带有空间压缩整理的能力决定。
但是仅仅修改一个指针所指向的位置来分配内存,在频繁创建对象的过程中,并发情况下不是线程安全的。解决这个问题有两种方案:对象分配内存空间的动作进行同步,分配内存在线程划分的不同空间中进行(每个线程在堆中预先分配一小块内存,称为本地线程分配缓冲TLAB,只有TLAB用完了,分配新的TLAB时才需同步锁定)
-
内存分配完成后,初识化内存空间(不包含对象头)为零值,保证对象的实例字段在Java代码中可以不附初始值可直接使用
-
之后还需对对象进行必要的设置。如,设置 这个对象是哪个类的实例、如何才能找到类的元数据信息、对象的哈希码、对象的GC分代年龄等信息。,这些设置存放在对象头中
-
接着执行构造函数,按照意愿对对象初始化,至此对象完全创建完毕。