JVM相关知识---对象

1. 对象的创建

   在我们一般创建对象是就是只需要new就可以,但是在虚拟机内部,需要很多步骤来把这个对象创建出来。首先,虚拟机会会根据new这个指令检查这个指令的参数是否在常量池中可以定位到一个类的符号引用。并且被加载、解析初始化过,如果没有则执行类加载。

   类加载后,虚拟机就该为对象分配空间了。有两种分配空间的方式,一种是“指针碰撞”,一种是“空闲列表”。何为指针碰撞? 首先假设内存空间是规整的,那么就把空闲与分空闲的区域分开存放,空闲的放在一边,非空闲的放在一边,在这两个区域的临界出有一个指针,当有一个新的对象要存进来的时候,指针就会根据大小往空闲的地方移一点。采取指针碰撞的前提就是内存是规整的,如果不规整就没办法了,但是可以用“空闲列表”。空闲列表是指,虚拟机会维护一个列表,在这个表上会记录着内存中哪块是使用过的,哪块是没使用过的,新建的对象就会根据这个表选择合适的位置存储。

   在分配内存时,还应该考虑到一个问题:再给一个对象分配内存的同时,另一个对象也要内存。这个解决办法也有两种,一种是采用同步处理-----虚拟机采用CAS配上配上失败重试的方式保证更新操作的原子性。另一种是先为每个线程在对上分配一小块内存,称为本地线程分配缓冲(TLAB)。哪个线程要分配内存就用哪个TLAB这个,只有TLAB用完分配新的时才需要同步锁定。分配完成后虚拟机要把分配完的内存初始化为零,保证程序不赋值也可以使用。

 

2. 对象的内存布局

   在HotSpot虚拟机中对象分为三个区域:对象头、实例数据、对齐填充

   对象头包含两个部分,一部分用于存储对象自身的运行时数据,如哈希码、GC分代年龄、所状态标志、线程持有的锁。偏向线程ID等等。这部分在32位和64位的虚拟机中分别占用32bit和64bit.

   另一部分是指针类型,虚拟机通过这个指针确定这个对象是哪个类的实例。但并不是所有的虚拟机都通过这个指针去找实例。另外,如果是数组对象,对象头还应该有一个记录数组长度的数据。虚拟机可以通过java对象元数据信息确定大小,但是不可以通过元数据确定数组的大小。

   实例数据是存储对象真正的有效信息,就是程序所定义的所有变量,无论是自己的,还是从父类继承下来的。

   对齐填充并没有实际用处,就是根据jvm对齐地址的。

 

3. 对象访问

   对象访问的方式也分为两种,一种是直接指针访问,另一种是使用句柄。都是通过栈上的reference数据指向对象实例,然后操作。

   其实这两个的区别就是一个直接指向对象,另一个有一个叫做句柄池的“管理员”,先都指向句柄,而后通过句柄再去找对象实例。

   下面我用两个图来说明:

 

                直接指向


             通过句柄指向