HotSpot虚拟机对象探秘
对象的创建
对象的创建对于我们程序员来说通常就是一个new关键字而已,在虚拟机层面,对象可不仅仅是new那么简单,Jvm可以说是一个非常复杂的过程,可以从三个角度来分析。
内存空间完整性
虚拟机在创建对象首先要为其分配内存,一种是通过“指针碰撞”,在内存中放一个指针这种内存一般都是规整的,随着空闲空间去边移动变记录,另一种是维护一个“空闲列表”,这种方式的内存不需要是规整的,用这个空闲列表去记录空闲空间,维护空闲列表由是否带有空间整理的能力决定
创建过程的线程安全问题
可能出现正在给对象A分配内存,指针还没来得及修改,对象B又同时使用了原来的指针来分配内存的情况。解决这个问题有两种可选方案:一种是对分配内存空间的动作进行同步处理——实际上虚拟机是采用CAS配上失败重试的方式保证更新操作的原子性;另外一种是把内存分配的动作按照线程划分在不同的空间之中进行,即每个线程在Java堆中预先分配一小块内存,称为本地线程分配缓冲(Thread Local Allocation Buffer,TLAB),哪个线程要分配内存,就在哪个线程的本地缓冲区中分配,只有本地缓冲区用完了,分配新的缓存区时才需要同步锁定。虚拟机是否使用TLAB,可以通过-XX:+/-UseTLAB参数来设定。内存分配完成之后,虚拟机必须将分配到的内存空间(但不包括对象头)都初始化为零值,如果使用了TLAB的话,这一项工作也可以提前至TLAB分配时顺便进行。这步操作保证了对象的实例字段在Java代码中可以不赋初始值就直接使用,使程序能访问到这些字段的数据类型所对应的零值。
对对象进行设置
Java虚拟机还要对对象进行必要的设置,例如这个对象是哪个类的实例、
如何才能找到类的元数据信息、对象的哈希码(实际上对象的哈希码会延后到真正调用Object::hashCode()方法时才计算)、对象的GC分代年龄等信息这些信息存放在对象的对象头 (Object Header)之中。根据虚拟机当前运行状态的不同,如是否启用偏向锁等,对象头会有不同的设置方式。