当我们new一个对象的时候,看似很简单,加上IDE的自动补全,怕是一秒左右就完成了。但是JVM遇到这条new指令的时候可是做了不少事情的。
1.首先,JVM回去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已被加载、解析和初始化过。如果没有就必须先执行相应的类加载过程。
2.当类加载检查通过之后,JVM将给新生的对象分配内存空间,对象所需要的内存大小在类加载完成后就可以完全确定了。
而在分配空间这里,等同于把一块确定大小的内存从java堆中划分出来,这里又有两种分配方式:
(1).指针碰撞式
如果Java堆中内存绝对规整的,堆中所有用过的内存都放在一边,空闲的内存放在另一边,中间有一个指针作为分界点的指示器,分配内存的过程就是将把指针向空闲的的空间那边挪动一段与对象大小相等的距离,这种分配方式如下图:
图一 配前
图二 分配后
(2)空闲列表
那如果Java堆内存不是规整的,而是空闲的和已使用的内存是相互交错的,那就没有办法用指针碰撞的方式来分配内存。所以就有另外一种方式,JVM必须维护一个列表,列表记录着哪些内存是可用的,然后根据记录找到足够存放对象大小的内存空间,划分给对象,并且在列表中进行登记。
图三 分配前
图四 分配后
3.当内存分配完成后,JVM就将分配到的内存空间都初始化为零值(不包括对象头)。
4.接下来JVM将对对象进行必要的设置,不如设置对象属于哪个类的实例,对象的哈希码,对象的GC分代年龄等信息,这些信息放在了对象头中。
5.对于JVM来说,到此已经产生了一个新的对象,但是对于Java程序来说,对象的创建才刚刚开始,<init>方法还没有执行,所有的字段都为零。执行new指令之后接着执行<init> 方法,把对象按照程序员的意愿进行初始化,这样子一个真正可用的对象就算完全产生出来了