在计算机发展的早期阶段,硬件的发展速度慢,容量小,所以软件开发人员写起代码里对 byte、bit 都是「斤斤计较」,这才使用写出来的应用能在我们今天看起来那么小的,配置那么低的硬件中运行良好,同时效果惊人。
那么计算机发展到今天,硬件看似配置越来越高,但依然架不住你随意写,搞不好应用就挂了。另外像游戏等一些行业还是「锱铢必较」,让应用能 稳定的运行。在Java 应用里,要想精确计算,需要对于对象的占用大小做到心里有数。那这篇文章一起来看看, 在 Java 的世界里,一个对象的大小究竟是多少呢?有哪些方式能够计算对象大小。
要看一个对象的大小,首先需要看Java 运行的平台是 32位还是 64位的 ,其次还要看对象内有多少属性(field)。最后还有一些 JVM 自身需要 在对象里记录的信息,比如说有GC的状态、同步状态、数组长度等等多种信息。这些项汇总求和,基本就是一个对象的大小了。不过VM为了效率,会采用固定长度,比如 8 位的整数倍来统一存储。这种情况下,如果原对象大小不足时,就会扩展对齐来存储。
好的,下面来看下 JVM 里,一个Java 对象大小占用多少。
由于现在基本操作系统基本都是64位,咱们后面都以64位 JVM 来说明。
首先来看两个例子
public class App {}
public class App { private byte a; private int b;}
例子1里, App 这个对象占用内存大小是多少 byte 呢?答案是 16。例子2 又是多少呢?答案是 24。
这里是怎么计算的呢?
计算方式
和开头的文字描述类似,在Java 里一个对象大小,是由这些内容组成
一个对象Object 大小 = Header + Primitive Fields + Reference Fields + Alignment & Padding`
其中的 Header 部分,就是 JVM 用于记录特定信息的,一版也叫做 object header
,在 OpenJDK 的汇总页里,描述是这样的:
Common structure at the beginning of every GC-managed heap object. (Every oop points to an object header.) Includes fundamental information about the heap object's layout, type, GC state, synchronization state, and identity hash code. Consists of two words. In arrays it is immediately followed by a length field. Note that both Java objects and VM-internal objects have a common object header format.
我们看到 object header
由这些部分组成:
mark word
klass pointer
(Optinal) 如果是数组,会记录数组的长度
mark word
The first word of every object header. Usually a set of bitfields including synchronization state and identity hash code. May also be a pointer (with characteristic low bit encoding) to synchronization related information. During GC, may contain GC state bits.
klass pointer
The second word of every object header. Points to another object (a metaobject) which describes the layout and behavior of the original object. For Java objects, the "klass" contains a C++ style "vtable".
总结一下,对象头里,基本是 GC的状态、同步状态、identity hash code,数组长度,以及 class 元信息的指针。
header 的长度由两个 word
组成。mark word 在 64位VM里,长度是 8 bytes。klass pointer 的长度64位VM下受参数-XX:+UseCompressedOops
配置控制, 可能是 4 bytes,也可能是8 bytes。
例子1&