Java对象在内存中占用的空间分为三类:对象头、实例数据和对齐填充

对象头:对象头主要分为两部分:markword、klass,如果对象是一个数组,那么还有一块空间用来存储数组长度
1.markword:存储对象自身的一些标识数据,如哈希码、GC分代年龄、锁状态标志、偏向线程ID等信息,在64位系统下占8个字节,下图是markword在不同情况下存储的内容

2.klass:储存指向这个类元信息的指针,占用8个字节,如开启指针压缩(默认开启-XX:+UseCompressedOops)则占用4个字节
3.数组长度:如果对象是数组,记录对象的大小,占用4个字节

实例数据:实例数据部分是对象真正存储的有效信息,也是在程序代码中所定义的各种类型的字段内容。

对齐填充:最后一块对齐填充空间并不是必然存在的,也没有特别的含义,它仅仅起着占位符的作用。这是由于HotSpot VM的自动内存管理系统要求对象起始地址必须是8字节的整数倍。

空的String占用的空间大小计算:

对象头(8 字节)+ 引用 (4 字节 ) + char 数组(16 字节)+ 1个 int(4字节)+ 1个long(8字节)= 40 字节,8的倍数不用填充

非空String占用的空间为:40 + 2 * n(n为字符串长度)