本文主要考虑正常情况下一个对象在堆上的内存占用情况:对于下面的特殊情况不作讨论
1、某些情况下,JVM可能不会把对象存储在堆上:比如小的线程私有对象原则上会全部存储在栈或寄存器上,严格意义上说并不存在于java堆上
2、对象的内存占用可能依赖于它当前的状态,比如说它的同步锁是否处于竞争状态、是否正处于垃圾回收阶段(这些额外的“系统”数据不一定存储在java堆上)
在HotSpot虚拟机上,一个java对象的内存占用一般包括如下几部分:
1、一个对象头部信息(包括几字节的基本元信息)
2、原始类型字段的内存占用
3、引用字段的内存占用
4、对齐字节(padding):为了让每个对象的开始地址是字节的整数倍,减少对象指针占用的比特数,对象数据后面会添加一些“无用”的数据(字节),以实现对齐,即保证最终的字节大小是8的倍数
HotSpot虚拟机的对象头包含两部分信息:1、用于存储对象自身的运行时数据,这部分数据在32位和64位的虚拟机(未开启压缩指针)中分别为32bit和64bit。
2、类型指针,即对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例。注:如果java对象是一个数组,还必须包含用于记录数组长度的数据,因为java虚拟机可以从普通java对象的元数据信息确定对象的大小,但是从数组的元数据中却无法确定数组的大小。
下图描述了32bit下对象头的存储状态: