对象的创建在JVM中的执行过程

在new对象的时候,jvm中的具体执行过程如下:

  1. 类加载检查.在创建对象前,jvm会检查该类是否已经被加载在虚拟机中,如果没有的话就会去执行类加载;待类加载完成后才会在内存中创建这个对象的空间.原因是,每一个对象在创建之时,就已经决定了它所占用的内存空间,所以在创建对象前必须要先确认类加载完成,不然无法预留出确定的对象空间.另外的,在分配对象空间时,会涉及到分配空间方式的问题.目前主要有两种,一个是指针碰撞,另一个是本地线程缓冲,也就是TLAB(Thread Local Allocation Buffer).指针碰撞是将内存空间分为两部分,一部分是已经分配的对象空间,一部分是剩余的堆内存.每一个对象生成时,指针都会向右偏移一个对象的空间,但在多线程环境下,指针碰撞采用CAS锁失败重试的模式;而TLAB则是在堆内创建额外的空间用来标记线程的私有空间,以空间换时间.
  2. 内存分配后,虚拟机将分配到的空间都置为零值(不包括对象头),如果使用TLAB,这一过程也可以提前至TLAB分配时进行.这一步操作保证了对象的实例字段在Java代码中可以不赋初始值就直接使用,程序能访问到这些字段的数据类型所对应的零值.也就是给对象分配初始值的操作.
  3. 接下来虚拟机要对对象进行必要的设置,这个对象是哪个类的实例、如何才能找到类的元数据信息、对象的哈希吗、对象的GC分代年龄等信息.

对象的创建在JVM中的执行过程

对象内存中的存储的布局可以分为三个区域:对象头、实例数据和对齐填充.

  1. 对象头:分为两部分信息,第一部分用于存储对象运行时的数据(如果是对象数组,在头信息还要加上对象数组的长度),Mark Word在32位虚拟机和64位虚拟机的长度分别为32位和64位.在Mark Word中有2bit用于存储锁标志位,对应的锁的转换关系为:可偏向锁 -> 轻量级锁定 -> 膨胀(重量级锁).可偏向是当没有线程争抢该对象时的锁,而轻量级锁是有两个或多个线程争抢该资源时才会转变为轻量级锁.轻量级锁时,为自旋锁,等待占有资源的线程释放资源,而当自旋到一定程度时,会从轻量级锁转为重量级锁.重量级锁时,争抢资源的线程不会再自旋争抢,会转为阻塞态等待被唤醒.
  2. 实例数据:实例数据部分是对象真正存储的有效信息.
  3. 对齐填充:为了让这个对象占据一定的空间,也就是为了让对象占有完整的8字节的整数倍空间而存在的.本身没有什么意义.