对象的创建
JAVA是一门面向对象的编程语言,我们都知道通过一个关键字new就可以创建一个对象。创建对象的实质就是把一块确定大小的内存从堆中划分出来。
对象的内存布局
我们知道了创建出一个对象的本质了,那对象在内存中具体是怎么存储的呢?在HotSpot虚拟机中,对象在内存中存储的布局可以分为三块区域:对象头、实例数据和对齐填充。
对象头
-
第一部分用于存储对象自身的运行时数据,如哈希码、GC分代年龄、锁状态标志、线程持有的锁、偏向线程id、偏向时间戳等。
如下图所示HotSpot32虚拟机对象头
以上图为例,在HotSpot虚拟机中,如果对象处于未被锁定状态,那么32位的空间中25为用来存储对象哈希码,4位存储对象的分代年龄,为存储锁标志,1位固定为0。
上图解析: 对于上面这个图的解析,方便大家理解。就是说对象头一共有32位用来存储一些信息,当然这些信息与对象的内容信息毫无关系。这个信息是记录对象的,就像一个快递包裹的快递单,只是用来记录这个快递,和你快递里面要寄什么,寄多少毫无关系。上图的意思是说,通过锁标志位的信息,来决定剩余的30位存储什么。 这样说应该就很好理解了吧。比如锁标志位是00,剩余的30为就存指向栈中锁记录的指针。锁标志位为11时,剩余30位存储为空,不需要记录信息。但我们发现锁标志为有两个01,这两个01,也很好理解,两个01通过那一位固定为的不同表示不同的意义,来决定剩余的29为存储什么信息。 比如锁标志为都为01的情况下,固定位是0则剩余29位存储对象的哈希码和分代年龄。固定位为1时,剩余的29为存储线程ID、Epoch、分代年龄。
- 对象头的另一部分是类型指针,虚拟机通过这个指针来确定对象是哪个类的实例。并不是所有的虚拟机实现都必须在对象头上保留类型指针,所以查找对象元数据信息不一定要经过对象本身。
实例数据
实例数据部分是对象真正存储的有效信息
对齐填充
对齐填充并不是必然存在的,也没有特别含义,它仅仅起着占位符的作用。由于内存管理系统要求对象起始地址必须是8字节的整数倍,换句话说,就是对象的大小必须是8字节的整数倍。对象头正好是8字节的1倍或者2倍。因此对象实例数据部分没有对齐时,就需要通过对齐填充来补全。