https://juejin.cn/post/6844903817897574407

Java 对象并不只是包含我们在 class 中所定义那部分实例数据,还需要包含虚拟机所需要的一些额外信息以及空填充,即对象头(Header)、实体数据(Instance Data)和对齐填充(Padding)三个部分,如下图所示:

image.png

  1. 对象头中的 Mark Word 在 32 和 64 位的虚拟机中大小为 32bit 和 64bit,类型指针同理,在对象头中字段特性如下:

Mark Word 被设计成一个非固定的数据结构以便在极小的空间内存储尽量多的信息,它会根据对象的状态复用自己的存储空间。具体不同状态不同复用效果见下图

image.png

  1. 对象的实例数据才是用户可见的、可控制的,包括从所有父类(直到Object)中继承的,以及子类中定义的。需要注意的是所有的静态变量、局部变量和函数并不包含在对象内存的实例数据中:

静态变量和函数是属于类的,一个类只有一份,它在类加载的时候存进方法区。 函数作为类的元数据也存在方法区(同时会受到即时编译的影响)。 局部变量在方法执行时在栈中进行动态分配的,主要位置是局部变量表。

  1. 对齐填充并不是必然存在的,也没有特别的含义,它仅仅起着占位符的作用。由于HotSpot VM的自动内存管理系统要求对象起始地址必须是8字节的整数倍,换句话说,就是对象的大小必须是8字节的整数倍。而对象头部分正好是8字节的倍数(1倍或者2倍),因此,当对象实例数据部分没有对齐时,就需要通过对齐填充来补全。

C++ 中有一本广为流传的书《深入理解 C++ 对象模型》专门讲 C++ 对象模型的,整整写成了一本书。可见相对于 C++ 对象,Java 要容易的多。C++ 中要计算一个对象的大小,直接使用 sizeof 即可。而在 Java 中却不能那么直接,如果想更具体的了解 Java 对象在内存中的大小,请看 一个java对象占多大内存 这篇文章,自己实践下。其实,只要知道了对象在内存中的组成(头、实例数据和填充)、实例数据中各个字段类型的大小,就能轻易算出对象的整体大小。

作者:水目沾链接:https://juejin.cn/post/6844903817897574407来源:稀土掘金著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。