在HotSpot虚拟机中,对象在内存中的存储布局可以分为3块区域:对象头部、实例数据、对齐填充。
一、对象头部Header的布局
Mark Word |
Class 指针 |
在32位系统下,上面两部分各占4B;
在64位系统中,Mark Work占4B,class指针在开启指针压缩的时候占4B;为开启指针压缩的时候占8B.
1、Mark Word 存储对象自身的运行时数据信息,例如哈希码,GC分代年龄,锁状态标志,线程持有的锁,偏向线程ID。
2、Class 指针,通过该指针确定该对象是哪个类的实例。
另外,如果该对象是一个数组,那么还将会有一个数据来记录数组的长度4B(32bit)/8B(64bit)。
二、数据部分
在该字段中,无论是从父类继承下来的还是该类自身的,都需要记录下来,而这部分的存储顺序受虚拟机的分配策略和定义的顺序的影响。
默认分配策略:long/double -> int/float -> short/char -> byte/boolean -> Reference
如果设置了-XX:FieldsAllocationStyle=0(默认是1),那么引用就会放在最前面:
Reference -> long/double -> int/float -> short/char -> byte/boolean
结论:分配策略总是按照宽度由大到小的顺序排列,相同宽度的放在一起。
在有继承关系的对象中,只有一个头部,父类的属性分配到该对象中,这样才能通过父类访问他的属性。如果开启CompactFields,那么,子类中较窄的变量就会插到父列的变量的空隙中。
[[注]] 静态属性所占的空间通常不计算到对象本身的空间中,以为他的引用是在方法区。
属性的对齐,例如byte占用一个字节的空间,那么就会填充3字节实现对齐。(32bit系统)
三、对齐填充
Java对象在内存中将以8字节对齐,也就是对象的总大小必须是8字节的整数倍。