Java对象内存大小由对象头、实例数据、对齐填充三部分组成:对象头在64位+压缩指针下为16字节(Mark Word 8字节+Class Pointer 4字节,按8字节对齐补齐),实例数据按字段重排序后累加,最后整体向上对齐至8字节倍数。
Java对象占用的内存大小不是简单把字段加起来,而是受JVM实现、平台架构(32/64位)、是否开启指针压缩(-XX:+UseCompressedOops)等影响。估算时需分三块:对象头、实例数据、对齐填充。
对象头包含Mark Word和Class Pointer(类型指针),可能还有数组长度(仅数组对象)。常见情况如下:
注意:Mark Word在锁膨胀、GC标记等状态下会复用结构,但估算常规对象时按固定大小算即可。
就是所有非静态、非瞬态(non-static, non-transient)字段的大小,按JVM字段重排序后的布局算(不一定按代码顺序)。JVM会把相同宽度的字段归堆,从宽到窄排列,以减少填充。
/ boolean → 1字节(注意:不会被压缩成1 bit;每个boolean单独占1字节,不共享)例如:class A { long a; int b; byte c; Object d; } 开启压缩指针时,重排后可能是:a(8) + b(4) + c(1) + padding(3) + d(4) → 实例数据共20字节
JVM要求对象总大小是8字节的整数倍(即按8字节对齐)。这是为了CPU访问效率,尤其在多核缓存行(Cache Line)对齐时更关键。
记住这个常用组合(也是HotSpot Server VM默认):
比如空对象 new Object():头16字节 → 对齐后仍是16字节; new Integer(1):头16 + value(int,4) = 20 → 对齐为24字节。
基本上就这些。实际生产中可用JOL(Java Object Layout)工具验证,它能精确打印字段偏移、大小和对齐细节,比手算靠谱得多。